一、基础知识
1、继承
2、封装
3、多态
4、构造函数
5、static的关键字
1、什么时候才需要用static来修饰?
属于这个类,而不属于类的对象
使用非静态方法是对象出来以后了,更加的面向对象去编程
如果一个方法与所在的类的实例对象无关,那就是静态的
如果我们确实应该使用非静态的方法,但是在创建类时有确定只需要维护一份实例时,就需要用单例模式
2、场景:工具类实现加载
6、接口和抽象类
接口实现,有实现类 抽象类可以有具体类的实现方法
7、this和super关键字
this用来指向当前的实例化对象,this.name=name, 后面的name为方法的形参
super来调用父类的方法或者变量,在显示调用父类构造方法的时候,应该在第一句使用
8、重载和重写
重载是在一个类中多态性的一种体现,指在一个类中定义一个多个同名的方法,参数的方法列表不同
重写则是在子类与父类的关系,重新进行写,要求方法的参数列表相同
9、break、continue、以及return的区别?
break直接跳出当前的循环
continue停止当次的循环,回到循环的起始处,进入下一次的循环操作
return表示从一个方法返回,可以使程序控制返回到调用该方法的地方
10、Object有几种方法呢?
java语言是一种单继承结构语言,java中所有的类都只有一个祖先,这个祖先就是Object类
object主要有以下的对应的方法
Object() Object类的构造方法
clone用途是另存一个当前存在的对象。只有实现了Cloneable接口餐可以调用该方法,否则会抛出异常
getClass(),获得运行时的类型,一般是使用在反射的情况下
equals() 比较两个对象的内容是否相等
hashcode返回对象所在的物理地址,常会和equals方法同时进行重写,确保相等的对象拥有相等hashcode
wait()导致当前线程的等待,直到其他线程调用此对象的notify()方法或者notifyAll()方法
线程通信??
notify() 唤醒在此对象监视器上等待的单个线程
notifyAll() 唤醒在此对象监视器上等待的所有的线程
11、Collections和Arrays和StringUtils
分别对应着集合的工具类和数组的工具类
Arrays常用的工具类\
int[] a = new int{1,5,6,89,56};
- Arrays.toString(a) 直接打印数组,不能打印出来,打印出是一个对象,数组的遍历,取出其中每一个元素
- Arrays.sort()数组进行排序
- Arrays.equals()比较数组值是否相等
- Arrays.binarySearch()对排序好的数组进行二分查找
二、Java基本类型及字符串和数组
1、值传递和引用传递
值传递传递的相当于变量的副本,,对其修改不会修改实参的本身
引用传递传递的对象的地址,指的是同一块内存单元\
2、“==”、equals和hashcode的区别
== 当是简单的变量的时候判断的是值是否相等
当时引用类型的时候则是判断对象的地址是否相等
equals则是判断对象的值是否相等
3、String、StringBuffer、StringBuilder有什么区别
String st1 = new String(“abc”);
在内存中创建两个对象,一个在堆内存一个在常量池,常量池对应的是方法区的空间
== 用来比较两个变量的值是否相等,当用来比较的对象的时候,使用
的是equals()方法,==是比较的两个对象的地址是否相等
String st1 = "ab";\
String st2 = "abc";\
String st3 = st1 + "c";\
System.out.println(st2 == st3);\
System.out.println(st2.equals(st3));
false(拼接字符串使用了StringBuffer的append方法) true
其中String是用final关键字类修饰,是不可以改变的
StringBuffer是可变类,是线程安全的字符串操作类,每个StringBuffer对象都有一定的缓冲区容量。有缓冲区的安全
StringBuilder是可变的,线程不安全的
4、数组的初始化方式
boolean[ ] color = new boolean[15];
5、java中常用的包装类
Byte、Short、Integer、Long、Float、Double、Boolean、Character
int[ ] count = new int[5];
boolean[] count = new boolean[10];
List<Integer> list = new LinkedList[]; //链表数组
5、字符串和数组对应的length()和length
求解字符串的是s.length(),数组的array.length,集合的是size
字符串的判断空是null和“”,其中“”代表着空字符串,在堆空间也具有一定的内存
集合的判断空的方式是isEmpyt()-----list.isEmpty()
数组判断为空 array.length==0
6、浅拷贝和深拷贝
浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象 深拷贝是所有的都进行拷贝
- 再理解:浅拷贝仅仅只复制某个对象的引用,而不复制对象的本身,两个引用指向同一个对象
- 深拷贝:创造一个一模一样的对象,新对象和源对象不共享内存,修改新对象不会改变源对象
实现的方式
- 实现Cloneable接口
- 实现Serializable接口
三、进阶机制
1、反射机制
简单来说:反射就是在运行时获取类的信息
- 场景1:MyBatis可以让我们只写接口,不写实现类,就可以执行SQL
- 场景2:在类上加上@conpoent注解,Spring就帮你创建对象
通过反射获取类的方法
- Class.forName("类对应的全包名");
- 对象.getClass();
- ClassLoader.loader("包名"); //使用类加载器不去进行类的初始化,即静态变量和静态的初始化对象不会创建
通过反射获取类的方法并执行
//常用的,获取成员变量的方法
Class class = Class.forName("类的包名");
//实例化对象
Object object = class.newInstance();
Method method = object.getMethod("方法名",string.class);
//方法的执行
method.invoke(object,"方法中形参");
优点和缺点
优:动态的加载类 缺:破坏封装,可以获取到类的私有变量
2、代理机制
动态代理:JDK代理和CGLIB代理
区别:JDK代理需要有接口,而CGLIB不需要接口
JDK代理主要运用了反射的机制 通过加入InvocationHandler来处理
CGLIB用的则是字节码框架,通过修改字节码生成子类来处理
3、泛型机制
简单来说:在创建对象或调用方法的时候才能明确具体的类型
优点:
代码更加简洁,程序更加健壮,在运行期间不会出现ClassCastException异常
场景1、操作的集合的时候
场景2、组件的创建,做到足够的通用性,不知道用户传什么类型参数进来
写组件,离不开java的反射机制(能够在运行时获取信息),一般是泛型+反射来实现
场景3、代理工厂的创建
- 问题:泛型擦除
List<String> list=new ArrayList<>();
list.add("小花");
list.add("小狗");
//使用反射机制实现泛型的擦除
Class class=list.getClass();
Method method = class.getMethod("add",object.class);
method.invoke(list,21);
在类上的泛型一般是不会擦除的
4、注解机制
简单来说:是代码的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理
一般java原生的注解大多数用于标记和检查
提供的基本注解外,还提供了元注解,用Annotation,常用的注解有@Retention和@Target
@rention设置注解的生命周期
@Target表示这个注解可以修饰的地方
- 注意在编译、类加载和运行时是被读取,对应的是注解的三种级别,source、class、runtime。其中runtime 是我们常用的,使用反射来实现
四、java中的异常
1、error和Exception的区别
都是Throweable的子类
一道非常经典的面试题,NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
在类的加载过程中, JVM 或者 ClassLoader 无法找到对应的类时,都可能会引起这两种异常/错误,由于不同的 ClassLoader 会从不同的地方加载类,有时是错误的 CLASSPATH 类路径导致的这类错误,有时是某个库的 jar 包缺失引发这类错误。NoClassDefFoundError 表示这个类在编译时期存在,但是在运行时却找不到此类,有时静态初始化块也会导致 NoClassDefFoundError 错误。、
JVM层面的错误不能用try catch来捕获 且是一个error
另一方面,ClassNotFoundException 与编译时期无关,当你尝试在运行时使用反射加载类时,ClassNotFoundException 就会出现。
运行时发生的错误,多发生在反射加载的过程中
2、finally关键字的作用
-
try语句定义所执行的进行错误测试的代码。如果 try 里面没有抛出异常,catch 将被跳过。 -
catch语句定义当try语句发生错误时,捕获该错误并对错误进行处理。只有当try抛出了错误,才会执行。 -
finally语句无论前面是否有异常都会执行, 所以一般不能在里面放置return语句,否则会覆盖前面的内容 补充final、finally、finalize有什么区别? -
final是一个关键字,修改得对象不允许修改或者替换原始值或定义
-
finally一般和try和catch一起使用,一般会一定执行,用在数据库的关闭连接
-
fianlize保证对象在垃圾回收前完成特定的资源回收 JDK9已经弃用,不能保证方法一定会运行
五、main方法与main线程
当JVM启动的时候,会启动一个名为“Main”的线程。程序就会在这个线程上运行,除非用户自己创建了其他线程。
Main线程首先就会寻找"static void main(String[] args)"方法,并且调用这个方法。这个就是程序的进入点。
如果我们希望程序可以并发,那么我们可以创建多线程,并且给予每个线程一些操作。接下来这些线程就会并发的执行这些操作。JVM同时也会创建一些其他的内部线程在“幕后”工作(比如垃圾回收)。
java中的两类线程
用户线程和守护线程
- 守护线程相当于保姆,注意每一个线程创建是运行在JVM中的,任何一个守护线程都是整个JVM中所有非守护线程的保姆,但不是所有的线程都可以有守护线程
- 最典型的守护线程是垃圾回收器,在守护线程中产生的线程还是守护线程
其中main线程是用户线程,可以自己定义
仅有main线程一个线程执行结束,不能决定JVM守护线程的退出,所以main方法并不一定是最后一个退出的进程