1. java语言特点?
# 三大特点: 笔试题 简单: 自动语法检查 自动垃圾回收机制 面向对象 一切皆对象 跨平台 可以在任意操作系统平台运行 jvm java virtual machine 简单 面向对象 跨平台 - 跨平台: JVM 实现跨平台标准 - 简单性: java语言强类型语言、自动语法检查、java支持自动垃圾回收机制 c++/c 自己处理垃圾回收 - 面向对象: 在java世界一切皆对象
2. java语言运行机制?
# 运行机制 笔试题 - 先编译然后解释运行 .java---> .class 文件 操作系统 jvm虚拟机 版本 window linux macos oralce hotspot g9 IBM虚拟机 ...
3. 什么是JVM?
# JVM: (Java Virtual Machine) java 虚拟机 jvm =====> ClassLoader类加载器 =====> .class - 1.JVM执行.class(子节码文件)的执行引擎 - 2.JVM屏蔽了底层操作系统 跨平台的重要体现
4. Java的命名规范?
字母 数字 下划线 $ 不能以数字开头 严格区分大小写 注意: 最好不使用关键字 特殊字符
包名: 全部要小写
类名: 首字母大写 多个单词首字母大写
方法名: 驼峰命名法 首个单词首字母小写 以后单词首字母大写
变量名: 驼峰命名法
常量名: 全部大写 String TIME_OUT =
# 注意: 包名全部小写,类名首字母大写(多个单词首字母大写),方法/变量驼峰命名(第一个单词首字母小写,以后单词首字母大写),常量全大写多个单词使用_分隔 com.baizhi.dao UserServiceImpl getMethod() static findal String USER_NAME = "xiaochen"; # 命名标识符 - 1)、名称只能由字母、数字、下划线、$符号组成 2)、命名时不能以数字开头 3)、在命名时绝对不能出现Java关键字。 4)、绝对不允许在命名时出现中文及拼音命名。 # 建议 1、项目名,包名全部小写 2、方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头 3、使用驼峰命名法命名多个单词组成的变量名 4、常量命名时需要遵循名称全部大写的原则 5、对于Service和DAO类,基于SOA(面向服务的架构)的理念,暴露出来的服务一定是接口,内部的实现类用Impl 的后缀与接口区别。 6、如果模块、 接口、类、方法使用了设计模式,在命名时需体现出具体模式 说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。 正例:public class OrderFactory; 工厂设计模式 public class LoginProxy; 代理设计模式 public class ResourceObserver;监听器设模式 7、定义数组时,类型与中括号紧挨相连 正例: int[] array = new int[10]; int array[] = new int[10]; // 不建议这样写
5.常见基本数据类型和对应字节
byte 1
short 2
int 4
long 8 0l
float 4 23.23F
double 8 23.23D
boolean 1 true false
char 2
# 基本数据类型 byte 1B 0 -128~~~127 short 2B 0 -32768~~~32767 int 4B 0 -2147483648~~~2147483647 long 8B 0L float 4B 0.0F|f double 8B 0.0===>1.2D|d boolean 1B false char 2B ‘\u0000’
# 测试题 - 1. 0.553423 这个是什么类型 ===>double 字面值double 2. short的取值范围是多少? ~32768===32767 3. int a=32766 a=a+3 a=? 32769 4. short a=32766; //一个数据类型一旦数据超过范围之后会从负数最小值开始变化 a++; ====> //32767 a++;//-32768 //自增 自减 无法自动类型提升 System.out.println(a); ====> -32768 short a=1; 1. a++; 2 2.a=a+1 编译报错 int 5. double a = 0.6454D; (正确) float f = 0.993434;(错误) 必须加入F|f 6. short a=12; a++;(正确) a=a+3;(错误) 解释:算数运行会自动类型提升 自增自减运算不会自动类型提升
6.自动类型提升?
# byte -> short -> int -> long -> float -> double - 当两个操作数有一个为double时,运算结果为 double 没有double,出现float, 结果为float 没有float,出现long, 结果为long 没有long,出现int, 结果为int 除long类型外, 其余整数类型运算结果均为int类型
7.&&与 & 、|| 和 |有什么区别?
# &&(与)、||(或)、!(非) ====> 逻辑运算 - 与: 两边同时为true 结果才是true - 或: 两边只要有一个结果为true 结果就是true - 非: 非真即假 # &、|、~ 、^ =============> 位运算 int a = 1 0000 0000 0000 0000 0000 0000 0000 0001 int b = 2 0000 0000 0000 0000 0000 0000 0000 0010 1&2 = 0 1|2 = 3 ~2 = -3 1^2 = 3 - &(与): 从最高位运算,运算符两个位都为1,结果才为1,否则结果为0 - |(或): 运算符两个位只要有一个为1,那么结果就是1,否则就为0 - “~”(非): 表示位为0,结果是1,如果位为1,结果是0 - “^”(异或): 表示的两个的位,相同则结果为0,不同则结果为1
8.冒泡排序 选择排序
1 3 2 6 7 4 5 9 必须背下来 # 冒泡排序思路: 两个相邻的元素比较,并且交换位置 for (int i = 0; i < a.length; i++) { for (int j = 0; j < a.length-1; j++) { if(a[j]>a[j+1]){ int tmp = a[j]; a[j] = a[j+1]; a[j+1] =tmp; } } } # 选择排序思路: 指定下标与所有数字比较 for (int i = 1; i < a.length; i++) { for (int j = i; j < a.length; j++) { if(a[i-1] > a[j]){ int tmp = a[i-1]; a[i-1] = a[j]; a[j] = tmp; } } }
9.数组扩容的思想?
# 1.创建更大数组进行搬家 int[] a = {12,23,23,345}; int[] b = new int[a.lenght*2] # 2.java.util.Arrays.copyOf(原数组名,新数组长度); # 3.System.arraycopy(原数组名,起始下标,新数组名,起始下标,复制长度);
10.面向对象的三大特性
# 1.封装 继承 多态 - 封装: 提高类和系统安装性 体现: 属性私有 提供公开的GET和SET方法 - 继承: 建立类的层次和等级方便扩展 体现: 子类继承父类 单继承一个子类只允许存在一个父类 - 多态: 父类引用指向子类对象 体现: 父类引用调用父类中方法 实际执行时执行的是子类覆盖之后方法
11.什么多态
# 多态: 父类引用指向子类对象 class Animal{ public void eat(){.. Animal eat} } class Dog extends Animal{ public void eat(){.. Dog eat} public void play(){....} } class Cat extends Animal{ public void eat(){.. Cat eat} public void runing(){...} } Animal a = new Dog(); a.eat(); //Dog eat Animal b = new Cat(); b.eat(); //cat eat 引用调用引用类中声明方法 在实际执行时执行子类覆盖之后方法
12.关于构造方法?
# 构造方法 作用: 用来创建对象 特点: 1.构造方法没有返回值 2.方法名必须和类名一致 3.不允许手动调用,在创建对象时自动调用 new Student(); 4.当在类中没定义任何构造方法时,系统会默认分配一个 公共无参的 构造方法 注意:一旦类中显示定义构造方法 默认的构造方法则不存在
13.this、super关键字
# this: 当前引用 指的:我 - this.属性名 this.方法名: 用于在构造方法或普通方法中,调用当前对象的属性或方法 - this(): 只能用在构造方法中,只能出现在构造方法第一行 代表调用本类中构造方法 # super: 父类引用 指的父类对象 - super.属性 super.方法 : 用在子类的构造方法或普通方法中,调用父类的属性或方法 - super() : 只能用在构造方法中,只能出现在构造方法第一行 代表调用父类中构造方法 注意:this() super()不能同时出现
14.继承时对象的创建过程?
# 对象创建过程 - 分配空间 - 初始化属性默认值 - 调用构造方法 # 继承时对象的创建过程 - 分配空间 (父子类空间一起分配) - 初始化父类属性 - 调用父类构造方法(创建父类对象) - 初始化子类属性 - 调用子类构造方法(创建子类对象)
15.java中继承关系
# java中类单继承 - 一个类只能存在一个父类 但是可以实现多个接口 # java中接口多继承 - 一个接口可以继承多个接口 # 为什么接口可以多继承 - 因为接口定义的都是抽象的方法,而且不能在接口中实现方法。所以,接口继承多个接口,并不会使接口的结构变得很复杂。 类 extends 父类 implemplents interface,interface1 # 为什么JAVA只能单继承? - 因为在C++中一个类是可以继承自多个类,但这样的机制会使类的结构变的很复杂,所以JAVA将C++这一机制通过接口得以改善。 JAVA中不允许类多重继承,只能单一继承,但有些情况单一继承并不能表达出现实世界中的某些逻辑关系,所以就提出了通过接口来实现多重继承。
16.overload(重载)、override(覆盖)?
# overload: 方法重载 - 方法名相同参数列表不同(参数个数,类型,顺序) 和 返回值无关 # override: 方法覆盖 方法重写 - 方法名相同 参数列表相同 返回值相同 访问权限修饰相同或更宽 抛出异常相同或更少
18.instanceof关键字作用? transient关键字作用?
# instanceof - 用来判断引用实际类型是什么 用法: a instanceof Dog 返回值: 类型一致 true 不一致 false if(a instanceof Dog){ } Animal a = new Dog(); a intanceof Dog Animal b = new Cat(); # transient - 用来作用于成员变量属性上,代表这个属性在对象序列化时不参与对象序列化
19.三大修饰符
# static: 静态的 - 类 : 静态类 - 属性 : 静态属性 全类共享 可以直接使用类名.属性名 直接使用 - 方法 : 静态方法: 全类共享 可以直接使用类型.方法名 直接调用 - 代码块: 静态代码: 静态在类加载时候执行, 只执行一次 # final: 最终的 - 类: 最终类: (断子绝孙) 该类不能被继承 - 属性: 最终的属性: 属性一旦被赋值不能被修改 - 方法: 最终方法: 可以被继承,不能被覆盖 try{}catch(Exception e){}finally{} //总是被执行 finallize() //在jvm垃圾回收自动调用 # abstract: 抽象的 - 类: 抽象类: 不能通过new关键创建对象 - 方法: 抽象方法: 只有声明没有实现 注意: 1.抽象类中一定含有抽象方法 不对 2.存在抽象方法类一定时抽象类 对 3.抽象类中存在构造方法 对 4.抽象类中因为不能通过new创建对象,因此类中没有构造方法 不对 5.抽象类中构造方法用来干什么? 用来为子类继承时创建子类对象用的 6.String 类能不能被继承? 不能被继承 final 关键字 为什么使用final关键字修饰? 字符串类中所有方法都是线程安全的方法,如果允许继承,可能会破坏string 中线程安全 #面试 * 1.存在抽象方法类一定是抽象类 对 * 2.抽象类一定存在抽象方法 不对 * 3.被static修饰方法方法内只能使用外部静态成员 对 * 4.普通方法可以直接使用static修饰方法 对 * 5.static修饰方法可以直接使用外部普通方法 不对 * 6.jdk中String类可以被继承? 不能 为什么String要设计成final的 String 不可变字符串 String name="小陈" name+"xiaohei"; * 7.抽象类中没有构造方法? 存在,子类继承父类时 创建父类对象使用
20.静态代码块,动态代码块,构造方法的执行顺序
public class Student extends People{ //静态代码块: 类加载时候执行 只执行一次 类加载: jvm第一次使用到这个.class文件进行类加载 classLoader ===> jvm static{ System.out.println("1"); } //对象: 初始化属性 调用构造方法 //动态代码块: 作用:用来给类中属性 赋值的 { System.out.println("2"); } //构造方法: 创建对象的时候自动执行 public Student() { System.out.println("3"); } public static void main(String[] args) { Student student = new Student();//5 1 6 4 2 3 } } class People{ static { System.out.println("5"); } { System.out.println("6"); } public People() { System.out.println("4"); } }
21.下面代码的执行顺序
public class Test{ private String name; static{ System.out.println("1"); } { name = "小陈"; System.out.println("2"); } public Test() { System.out.println("3"); } public static void main(String[] args) { new Test(); } }
# 解释: - 1.当jvm第一次读取类信息时会执行类加载,static代码块是在类加载时候执行,因此最先执行输出1 - 2.{}代码块: 初始化代码块,在创建对象时为属性进行初始化执行,因此创建对象之前要先经历属性初始化才创建对象因此输出2 - 3.构造方法: 在创建对象时自动调用,最后输出3
22.什么是类加载?
# 类加载 - 类加载,在JVM第1次使用某个类时,先在classpath下 找到对应的.class文件,读取 该.class文件中的内容(包/名/属性/方法...)到内存中 并且保存(类对象)起来的过程。 类加载只进行1次
23.简述 final finalized finally 的区别?
# final 最终的 - 类: 修饰不能被继承 - 属性: 最终属性 一旦被赋值不能被修改 - 方法:最终方法 可以被继承不能覆盖 - String类能不能被继承? 不能 原因是:被final关键字修饰的 - String:为什么要设计成final? String不希望有子类,子类会破坏父类中方法规则 原因:字符串类中所有方法都是线程安全的,如果存在子类破坏父类中方法线程安全 # finalized 垃圾回收时jvm自动执行的方法 # finally 最终的 一般 try catch 进行连用 try{}finally{} - finally 代码中的内容: 无论什么情况总是执行
24.接口和抽象类区别
# interface 接口 - 1.接口之前可以多继承 interface A extends B,C... 2.类 implements A,B,... - 2.接口中定义变量都是静态常量 接口中变量都是被 public static final String NAME = "xiaochen"; 修饰的 静态常量 - 3.接口中方法公开抽象方法 只有声明没有实现 (jdk8) (jdk8)以后,接口中方法可以存在默认实现 # 抽象类 abstract - 1.类中含有构造方法 - 2.抽象类只能单继承 - 3.抽象类存在普通方法 - 4.抽象类中存在抽象方法 只有声明 没有实现的
25.”==”与equals有何区别?
# == - 比较地址内存地址 user1 == user2 # equals - 比较内容是否一致 user1.equals(user2); //比较对象:必须覆盖euqals 和 hashCode方法
26.StringBuilder与Stringbuffer的区别?
# StringBuilder 、 StringBuffer - 共同点: 都是用来进行字符串拼接的 - 不同点: 1.StringBuilder 线程不安全 效率高 2.StringBuffer 线程安全 效率低
27.简述ArrayList、LinkedList、Vector三者的区别?
# ArrayList LinkedList Vector 都是List接口实现类 都是集合 - ArrayList: 底层实现: 数组 特点:一段连续内存空间 根据下标快速查询 查询快(O(1)) 增删慢 O(n) 线程不安全 - LinkedList: 底层实现: 链表 特点:指针概念将节点连接在一起 增删快(O(1)) 查询慢(O(n)) - Vector: 底层实现: 数组 特点: 一段连续内存空间 根据下标快速查询 查询快(O(1)) 增删慢 O(n) 线程安全
28.HashMap和HashTable的区别?
# hashmap - 线程不安全的 允许key value 同时为null # hashtable - 线程安全的 不允许key value 同时为null # ConcurrentHashMap(并发hashmap) 线程安全 效率 hashtable - 线程安全的 效率远高于hashtable Hashtable和ConcurrentHashMap有什么分别呢?它们都可以用于多线程的环境, 但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。数组+链表 因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,对表进行分段加锁16段 而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。
29.HashSet如何实现元素不重复?
# 自定义类型 - 需要在类中覆盖hashcode和equals方法 # 非自定义类型 - 内部底层自动覆盖hashcode 和 equals
30.简述流的分类?
# 方向 - 输入流: 将数据读入jvm中 - 输出流: 将jvm中数据写出 # 功能 - 节点流 : 实际负责传输数据的流 - 过滤流 : 增强节点流功能(处理流、装饰类),依赖节点流 # 单位 - 字节流: 读取一切数据 - 字符流: 读取文本类型的数据 InputStream is = new FileInputStream("") OutputStream os = new FileOutputStream("") 文件拷贝代码 1.定义输入流 定义输出流 InputStream is = new FileInputStream(new File("d://aa.txt")); 900byte OutputStream os = new FileOutputStream(new File("e://bb.txt")); 2.文件拷贝 byte[] b = new byte[1024]; //1KB int len = 0; while(true){ len = is.read(b); if(len=-1)break; os.write(b,0,len); } //2.IOUtils.copy(is,os); //引入commons-io工具包 3.释放资源 is.close(); os.close();
31.什么是线程?
# 线程 - 进程: 一个进程中可以化分为多个线程 线程是程序调度基本单位 - 多线程: 可以提高程序运行效率 new Thread(()=>{ }).start(); java中实现多线程方式: 1.继承Thread类 2.实现runable接口 3.线程池 4.线程辅助类 FeatureTask Callable # 线程状态 5种状态(操作系统角度) - NEW 新建状态 - RUNNABLE start方法之后进入 可运行状态 - RUNNING 获取cpu时间片 运行状态 - BLOCKED Thread.sleep(1000); IO ... 阻塞状态 - DEAD 死亡状态
32.什么是线程安全?
# 线程安全 - 如果你的代码所在的进程中有多个线程在同时运行, 而这些线程可能会同时运行这段代码。 如果每次运行结果和单线程运行的结果是一样的, 而且其他的变量的值也和预期的是一样的,就是线程安全的。 一个线程安全的计数器类的 同一个实例对象在被多个线程使用的情况下也不会出现计算失误。
33.线程安全案例
类对象唯一,可以使用类对象加锁
类对象在jvm就一个,唯一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gtCivnQq-1640409536714)(image/image.png)]
对象锁
public class TestThread { private static int count = 0; private static Object o = new Object(); //synchronized (对象) 对象锁 public static synchronized void main(String[] args) throws InterruptedException { synchronized(TestThread.class){ // getstatic +1 value putstatic t1 Thread t1 = new Thread(() -> { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o){ for (int i = 0; i < 10000; i++) { count++; } } }); Thread t2 = new Thread(() -> { //t2 synchronized (o) { for (int i = 0; i < 10000; i++) { count--; } } }); t1.start(); t2.start(); t1.join();//阻塞main等待线程执行完成 t2.join();//阻塞main等待线程执行完成 System.out.println(count); } }
34.实现多线程方式
# 1.继承Thread类
Thread1 extends Thread { public void run(){ // 线程的功能代码 } } //使用:a. 创建线程对象 Thread1 t1 = new Thread1(); //b. 启动线程 t1.start(); // 启动线程,JVM自动调用run方法 // t1.run(); //error. 相当于调用了一个对象中的方法
# 2.实现Runable接口
Thread2 implements Runnable{ //实现run方法 @Override public void run(){ //线程的代码功能 } } //使用 Thread thread = new Thread(new Thread2()); thread.start();
# 3.实现 Callable 接口
Thread1 implements Callable { public void run(){ // 线程的功能代码 } } //使用:a. 创建线程对象 Thread1 t1 = new Thread1(); //b. 启动线程 t1.start(); // 启动线程,JVM自动调用run方法 // t1.run(); //error. 相当于调用了一个对象中的方法
# 4.使用FeaturTask - 获取线程执行任务结果
//线程任务对象 FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+ "-----------"); return 10; } }); new Thread(futureTask).start(); System.out.println(futureTask.get());
35.sleep() 和 wait() 有什么区别
# 共同点: 都是让线程进入等待状态 sleep 有限期等待 wait 无限期等待 # sleep() 线程对象中方法 - 线程进入等待之后,不会释放对象锁,等待结束之后恢复线程继续执行 # wait() Object类中方法 - 线程进入等待之后,释放掉当前对象锁,只有接收notify() 或者notfiyall() 之后才能恢复运行,恢复运行时重新进入等待队列获取锁表标记
36.通过反射获取类对象的3种方式
# 反射获取对象 - 1)通过类名.class 获取 Class对象 Class s = Student.class; - 2)创建对象,通过对象 . getClass() 获取Class对象 Strudet student = new Student(); Class s = student.getClass(); - 3)通过 Class.forName("包名.类名"); 获取Class对象 Class s = Class.forName(“java.util.HashSet”);
37.单例设计模式
//只能创建一个对象
# 懒汉式
class User{ private static User user; private User(){} public synchronized static User getInstance(){ //存在线程安全问题:必须加入线程锁 if(user == null){ user = new User(); } return user; } }
# 恶汉式
class User{ private static final User user = new User(); private User(){} public static User getInstance(){ return user; } }
38.单例模式案例
public class TestSingleton { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(()->{ System.out.println(Dept.getInstance()); }).start(); } //懒汉式: 每次使用使用创建 存在线程安全的问题 class Dept{ private static Dept dept; private Dept(){} //t1 bb t2 aa public synchronized static Dept getInstance(){ if(dept==null){ dept = new Dept(); } return dept; } } //饿汉式 : 不管用还是不用 直接创建一个实例 不存在线程安全问题 class Emp{ private static final Emp emp = new Emp(); private Emp(){}//构造方法私有 //返回一个对象 public static Emp getInstance(){ return emp; } }
Java Web
39.Oracle 中主键的自动生成策略是什么?如何创建?
# sequence 序列 oracle中主键生成策略 1. 创建 create sequence seq_user start with 1 increment by 2 maxvalue 100 minvalue 1; 2. 使用 sequence 序列名.nextval 使用下一个序列值 insert into t_user values(seq_user.nextval 序列名 .currval //获取当前序列的数值 前提序列必须先执行过一次 select 序列名.currval from dual; 注意:序列一旦被创建可以在任意表中使用,值一旦产生不能重复获取。 # mysql主键策略 自动生成 auto_increment mysql自动生成 create table t_user( id int(4) primary key auto_incrment, name ) insert into t_user('name') values('xiaochen')
40.select语句执行顺序
# select语句 - 书写顺序: select * from 表名 where 条件 group by 分组 having 条件2 order by 排序 - 执行顺序: from 表名 where 条件 group by 分组 having 条件2 select order by 1.FROM 确定查询的表 2.WHERE 对数据按条件筛选 3.GROUP BY 对筛选后的数据分组 4.HAVING 对分组后的数据再次进行筛选 5.SELECT 生成结果集 6.ORDER BY 对结果集进行排序
41.什么是 ACID ?
ACID: 原子性 隔离性 一致性 持久性
# 事务四个特性 - ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。 1. 原子性 Atomic 事务必须是原子工作单元 ( 不可分割 ) ;对于其数据修改,要么全都执行,要么全都不执行。 2. 一致性 Consistent 操作前的数据,操作后的数据保持一致。 3. 隔离性 Insulation 保证多用户并发访问的数据安全性,并发事务所作的修改必须与任何其它并发事务所作的修改隔离。 4. 持久性 Duration 事务操作的数据 持久化到数据库当中 , 对于系统的影响是永久性的。
42.事务隔离级别
# 事务隔离级别 - read_uncommit 读未提交: 一个客户端读取到了另一个客户端没有提交的数据 脏读现象 client1 insert clinet2 - read_commit 读提交: 一个客户端只能读取另一个客户端提交之后的数据 避免脏读现象 oracle默认隔离级别 - repeat_read 可重复读: 一个客户端在一次事务多次读取同一条记录多次读取结果一致 避免不可重复读现象出现的 mysql数据默认隔离级别 zhangsan 1000 client1 clinet2 100 300 commit 100 - serialiable 序列化读(串度):一个客户端再一次事务中多次读取同一张表记录,多次读取结果一致 避免幻影读现象 table 1 zhangsan client1 client2 1 insert commit 注意:隔离级别越高查询效率越低
43.sql优化方案
# 优化方案 - (1)选择最有效率的表名顺序 user video category (2)当只需要一行数据时候使用limit 1; (3)SELECT子句中避免使用‘*’ (4)用Where子句替换HAVING子句 (5)通过内部函数提高SQL效率 concat... max min ... (6)避免在索引列上使用计算。 //在索引列进行计算会导致索引失效 (7)提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。
44.什么是sql注入?,如何防止sql注入
# sql注入 ?name=xiaoor1=1 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 [1] 比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击. mybatis 必须使用#{} 避免sql注入 mybatis ${} 什么时候用这个获取数据? 如果将获取数据作为sql语句一部分执行就必须使用${} 存在sql注入 order by ${} # sql注入案例 user=request("user") ===> ss or a=a passwd=request("passwd") ===> 1234 or 1=1 sql="select admin from adminbate where user= 'ss or a=a' and passwd='1234 or 1=1'" pstm sql="select admin from adminbate where user= ss or a=a and passwd= 1234 or 1=1" statement 注意:在使用jdbc时使用statement对象执行sql才会出现sql注入 pstm: 通过占位符形式不会存在sql注入
45.JDBC核心步骤如何实现?
# 导入数据库驱动jar - 1.加载驱动。 Class.forName(“oracle.jdbc.OracleDriver”) - 2.创建数据库连接对象Connection Connection conn=DriverManager.getConnection(“”,”root”,”root”); jdbc:oracle:thin:@localhost:1521:xe jdbc:mysql://localhost:3306/库名?characterEncoding=UTF-8 - 3.创建Statement对象 PrpepareStatement String sql=”select * from user whnere username=?”; PrepareStatement pstm=Conn.prepareStatement(sql); Pstm.setString(1,name) - 4.执行Sql pstm.executeUpdate(); ResultSet rs = executeQuery(); - 5.处理结果集 - 6.释放资源 rs.close(); pstm.close(); conn.close();
46.jdbc是什么
JDBC 是java的13中规范之一(13个接口) 应用 Java 程序访问和操作数据库的底层代码 ,SUN 公司提出的一组规范 ( 接口 ) 。 1.1 接口规范:多种数据库产品, Sun 公司只是制定程序开发规则。 接口类型 : 屏蔽底层的代码实现差异 (访问不同的数据库) 1.2 实现在哪:驱动 Jar( 由数据库厂商提供 ) oracle ojdbc mysql mysql-connet sql JDBC = SUN 公司提出的一组规范 ( 接口 ) + 驱动 Jar
47.Statement 和 PreparedStatement 的区别
# 共同点: 都是用来执行sql语句的 - 1.Statement是PreparedStatement父接口 - 2.Statement使用sql拼接方式执行sql 存在sql注入 - 3.PreparedStatement 可以使用占位符,是预编译的,批处理比 Statement 效率高 . 防止 SQL 注入
48.事务控制
# 事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。原子性 - 1.JDBC中默认事务是一条Sql语句自成一个事务,即一条Sql语句执行完毕会自动提交事务;无法保证业务功能的完整。需要程序员手动控制事务: 1.1 设置手动控制事务: conn.setAutoCommit(false); 手动提交 1.2 手动提交事务:conn.commit(); 1.3 手动回滚事务:conn.rollback();
49. 三层架构MVC
# M:model 模型层 dao+service+entity jdbc # C:controller 控制层 servlet action 1.收集数据 2.调用业务 3.响应结果 # V:view 试图层 展示数据 html/Jsp ajax html ---> 接口 MVC
50. 自定义 servlet 的三种方式,及区别
# 方式一: implements Servlet 接口 ( 不建议 ) 实现接口中所有抽象方法 1 、 destroy() 2 、 init() 3 、 service() //service 方法 4 、 getServletConfig() 5 、 getServletInfo() # 方式二: extends GenericServlet , 覆盖 service 方法:不建议使用, 与 http 协议无关 service(ServletRequest req, ServletResponse res) # 方式三: extends Httpservlet 在这个抽象类中,所有的方法都是普通方法 只需要覆盖 service 方法 接受请求,处理请求、把结果响应给 Client{ 1.收集数据 2.调用业务对象 3.流程跳转 }
51. 连接池的作用
# 数据库连接的建立是一种耗时、性能低、代价高的操作,频繁的数据库连接的建立和关闭极大的影响了系统的性能。数据库连接池是系统初始化过程中创建一定数量的数据库连接放于连接池中,当程序需要访问数据库时,不再建立一个新的连接,而是从连接池中取出一个已建立的空闲连接,使用完毕后,程序将连接归还到连接池中,供其他请求使用,从而实现的资源的共享,连接的建立、断开都由连接池自身来管理。 # 数据库连接池为系统的运行带来了以下优势: 昂贵的数据库连接资源得到重用;减少了数据库连接建立和释放的时间开销, 提高了系统响应速度;统一的数据库连接管理,避免了连接资源的泄露。 tomcat: jndi 配置文件 dhcp c3p0 druid(阿里连接池)
52.Servlet 中的三大作用域对象是什么?及各自的作用范围?
# request: 一次请求有效 request # session: 一次回话有效 request.getSession() # application(servletContext): 全局共享 应用级作用域 唯一 request.getSession().getServletContext(); request.getServletContext();
53.表单提交两种方式
# Get 方式 get 传递数据的方式:通过地址栏传递,明文传递数据,不安全,传递的数据量少。 # Post 方式 post 传递数据的方式:通过请求体传递数据,密文传递数据,安全,传递的数量大。 - 如何解决javaweb开发中中文乱码问题? get方式: 在服务器tomcat配置文件servet.xml URIEncoding="UTF-8" tomcat8 默认已经 post方式: servlet request/response.setCharacterEncoding("") struts2 默认 springmvc springboot 自动配置 - 文件上传需要注意什么? 1.表单提交方式必须是post 2.form enctype="multipart/form-data"
ost解决中文乱码问题
class MyFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("UTF-8"); servletResponse.setCharacterEncoding("UTF-8"); filterChain.doFilter(servletRequest,servletResponse); } }
54.jsp 的 9 个隐含对象?
- 1 request 作用域相关的操作。 request.getContextPath();// 用于动态获取应用名(项目名) `<form method="post/get" action="<%= request.getContextPath()%>/url-pattern"> - 2 response( 不怎么用得上 ) response.getWriter();返回的是PrintWriter,这是一个打印输出流。 response.sendRedirect(); response.setContentType("text/html;charset=UTF-8"); - 3 session 作用域相关的操作。 - 4 application(ServletContext) - 5 (out) 等价于 <%= %> - 6 (cofig) ServletConfig 获得 Servlet 中初始化参数信息 web.xml - 7 (exception) 上一个界面发生的异常,只能在 isErrorPage 的页面中使用。 - 8 page page 只得是当前页面 类似于 this 。 - 9 pageContext 页面最小作用域 只在当前页面有效 ${pageContext.request.contextPath} ====> 获取项目路径 jsp
55.servlet 运行是单例 ?
# servlet: 单例 所有请求公用同一个servlet对象 - 注意: 单例 线程不安全 尽可能在使用servlet时尽可能避免使用成员变量操作数据 # struts2: 多例 一个请求一个新的实例对象 - 在struts2中使用大量成员变量收集数据 传递数据 多例避免多线程线程安全问题 # springmvc: 单例 - 在springmvc收集参数使用控制器方法形参列表 @RestController @Scope("singleton|prototype") xxxController
56.Struts2 框架面试知识点
# 1)简述struts2框架 Struts2是一个典型的mvc框架,在整个mvc框架中充当控制器的角色,struts2替换原生的servlet技术,是对原生servlet代码的合理封装。 # 2)Struts2的前置控制器的类名 重点 StrutsPrepareAndExecuteFilter /* # 3)Struts2的执行流程 后台接收到request,经过struts2的前置控制器strutsPrepareAndExecuteFilter解析请求路径,去struts2的配置文件中找对应的namespace和action的name属性,然后再找到对应的class和method,执行相关的代码,然后完成流程跳转。 # 4)Struts2如何接收参数 a.使用成员变量收集参数,需要提供相应的get/set方法 零散类型 对象属性 数组类型集合 # 5)如何在struts2中控制器的方法中获取request和response ServletActionContext.getRequest().getSession(); servletActionContext.getResponse() request.getSession().getServletContext(); # 6)Struts2的跳转方式 servlet中跳转 forward : 请求转发 特点: 一次请求 地址栏不变 服务器内部跳转 tomcat redirect: 请求重定向 特点: 多次请求 地址栏改变 客户端跳转 chrome Action--->jsp: forward:默认(dispatcher) <result name="success" >/index.jsp</result> redirect: type="redirect" <result name="success" >/index.jsp</result> Action--->Action forward: type="chain" redirect: type="redirectAction" <result name="ok" type="redirectAction|chain"> <param name="namespace">/xx</param> <param name="actionName">xxx</param> </result> # 7)Struts2中的拦截器 Interceptor 类似javaweb filter 作用: 将多个控制器中执行相同业务代码放入拦截器中执行 减少action中代码冗余 特点: 1.拦截器只能拦截控制器相关请求 jsp 静态资源 2.拦截器可以中断用户请求轨迹 3.请求到达经过拦截器,响应回来还会经过拦截器 MyInter implemenets Interceptor 注意: 拦截Action的相关请求 不能拦截jsp 自定义拦截器 A1 A2 自定义拦截器栈 stack 默认拦截器栈 extends="struts-default" 自定义拦截器栈 my-default-stack <interceptors> <interceptor name="myInter" class="com.baizhi.action.MyInter"></interceptor> <interceptor name="myInter1" class="com.baizhi.action.MyInter1"></interceptor> <!--自定拦截器栈--> <interceptor-stack name="aa"> <interceptor-ref name="myInter"> <interceptor-ref name="myInter1"> </intercrptor-stack> <!--系统拦截器栈--> <interceptor-stack name="aa"> <interceptor-ref name="defaultStack(系统拦截器)"/> <interceptor-ref name="myInter"/> <interceptor-ref name="myInter1"/> </interceptor-stack> </interceptors> <!--默认拦截器--> <default-interceptor-ref name="aa"/> # 8)Struts2中的文件上传与下载 文件上传注意事项: 1).导入jar包commons -io commonsfileupload 2).表单提交方式必须是post 3).表单enctype属性必须为multipart/form-data form method="post" enctype="multipart/form-data" input type="file" name="aaaa" 4).在Action中定义成员变量 private File aaaa; get set private String aaaaFileName get set 原始文件名 //1.根据相对路径获取绝对路径 String realPath = ServletActionContext.getServletContext().getRealPath("/back/photo"); //根据文件路径去找文件夹 File file = new File(realPath); //判断文件夹是否存在 if(!file.exists()){ file.mkdir(); } //获取文件名频接时间戳 String newName= new Date().getTime()+"."+FileNameUtils.getExtension(aaaaFileName); //文件上传 FileUtils.copyFile(aaa, new File(file,newName));