抽象类和普通类的区别
-
抽象类不能被实例化。-- 抽象类只在分配了在栈中的引用,没有分配堆中的内存
-
抽象类可以有构造函数,被继承时子类必须实现(调用)父类一个构造方法 — 《因为子类会继承父类的构造方法,如果父类方法中的构造函数是带有参数的,子类默认的构造函数会调用super(),在父类中是找不到的》
-
抽象方法不能被声明为静态 -- 抽象方法都没有主体,静态也就没有意义了
-
抽象类中可以允许普通方法有主体
-
含有抽象方法的类必须申明为抽象类
-
抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类
抽象类和接口的区别
-
抽象类和接口都不能直接实例化
-
接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
-
接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
-
抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
-
抽象方法只能声明,不能实现,接口是设计的结果 ,抽象类是重构的结果
-
抽象类里可以没有抽象方法
-
如果一个类里有抽象方法,那么这个类只能是抽象类
-
抽象方法要被实现,所以不能是静态的,也不能是私有的。
-
接口可继承接口,并可多继承接口,但类只能单根继承。
构造器,普通代码块,静态代码块的区别
-
无参数构造器:不写,系统会自动添加
-
有参数构造器:如果你定义了一个有参数的构造器,系统不会自动添加无参数构造器,那么在实例化对象的时候必须带上参数,不然会报错
-
构造代码块:对象一实例化就执行,每实例化一次执行一次
-
静态代码块:对象实例化就执行,无论new多少个对象,仅执行一次
-
无继承的初始化顺序:
-
静态代码块 > 普通代码块 > 构造器
-
有继承的初始化顺序:
-
父类静态代码块 > 子类静态代码块 > 父类普通代码块 > 父类构造器 > 子类普通代码块 > 子类构造器
静态变量和实例变量的区别
-
静态变量前要加static关键字,而实例变量前则不加
-
实例变量时实例化后才会分配空间,而静态变量当类加载的时候就分配内存空间
-
非static方法可以调用static方法
-
static方法不能访问非statis方法, 因为当一个static方法被调用时,可能还没有创建任何实例对象
为什么内部类有静态成员那么内部类必须是静态的
-
内部类是外部类的一个成员,可以等同于外部类的一个属性或者方法。
-
非静态的内部类是外部类对象的一个成员,必须先有外部类的对象才有这个内部类,它是属于对象的。
-
内部类的静态成员不属于对象的,也就是类在加载的时候就存在了,那么这就发生冲突了,也就是说外部类还没有new对象前,这个内部类是不存在的,而这个内部类的静态成员就存在了,这就好比没有鸡就先有鸡蛋一样。
-
普通内部类需要外部类声明的对象来创建内部类,静态内部类不需要
Java中private、protected、public、default区别
-
-
public:可以被所有其他类所访问
-
private:只能被自己访问和修改
-
protected:自身、子类及同一个包中类可以访问 ( 但是只能在子类的内部进行访问,即:(this.)方法名、(this.)属性名进行访问和操作)
-
default:同一包中的类可以访问,声明时没有加修饰符,认为是friendly。
使用final关键字修饰一个变量时,是引用变量不能变,还是引用对象不能变
-
是引用变量不能变,引用对象中的内容还是可以变的,比如StringBuffer
字符流和字节流的区别
-
字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
-
字节流默认不使用缓冲区;字符流使用缓冲区。
-
字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。
-
底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向IO设别写入或读取字符串提供了一点点方便。
“==”和“equals”区别
-
== : 如果判断值类型的话,判断内容是否相同。如果判断引用类型则是判断内存地址是否相同
-
equals : 判断内容是否相同
transient关键字有何作用
-
修饰不需要序列化的字段
反射
-
对于任意一个类,都能够知道这个类的所有属性和方法;对于任何一个对象都能够调用它的任意方法和属性;
-
在程序运行状态中,能够动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
-
运用场景:
-
做基础框架的时候会用得上,一般应用层面很少,不过这种东西,基本现在很多开源框架都已经给你封装好了,自己基本用不着写。Spring也用到了。经典的就是xml或者properties里面写上了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射,根据这个字符串获得某个类的实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了。
动态代理和静态代理的区别
-
静态代理的缺点
-
代理类和委托类实现了相同的接口方法,如果接口新增一个方法,所有的类都要实现这个方法
-
代理对象只服务于一种类型的对象
-
动态代理的优点
-
一个代理类完成全部接口和方法的代理功能
-
一个代理类能代理各种类型的对象
jdk动态代理和cglib动态代理的区别
-
代理模式:
-
代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。而AOP,是通过动态代理实现的。
-
区别:
-
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
-
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
-
Spring在选择JDK还是CGLib 的依据
-
当Bean实现接口时,Spring就会用JDK的动态代理
-
当Bean没有实现接口时,Spring使用CGlib是实现
-
可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
-
CGLib比JDK快?
-
使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类
-
在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
synchronized与Lock的区别
-
首先synchronized是java内置关键字,在jvm层面,Lock是个java类
-
synchronized无法判断是否获得锁的状态,Lock可以判断是否获取到锁
-
synchronized会自动释放锁(a 线程执行同步代码会释放;b线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()放啊释放锁),否则容易造成线程死锁
-
用synchronized一个线程堵塞了,其他线程会一直等待下去,Lock锁就不会一直等待下去,有些方法尝试几秒获取不到锁,不用一直等待就结束了
-
synchronized的锁可重入,不可中断,非公平,而Lock锁可重入,可判断,可公平