引用数据类型
定义:由类的编译器规定的,用于访问对象的这些变量,被称为不可更改的特定类型,与基础数据类型的区别就在于基础数据类型就是一个值而已
其实说白了,就是对象的引用变量,就这么简单,这个变量就是所谓引用数据类型。例:A a=new A(),a就是引用数据类型
Equals与==的区别
==是判断变量或实例是否指向同一内存空间,而equals是判断变量或者实例所指向的内存空间是否相等,前者判断的是引用是否是相同的,后者判断的是引用的值是否是相同的。
自动装箱与自动拆箱
自动装箱是基础类型赋值给包装类,自动拆箱就是包装类赋值给基础类型
Object的公用方法
Equals:Object的equals方法跟子类的==是一样的。
getClass:获取运行时类型
Wait:线程休眠,需要用notify 或者notify All来唤醒
toString:转换成字符串,一般子类都有重写,否则打印句柄。
hashCode:该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
Java对象的四种引用级别
强引用:String a=“123” a是123的强引用,该引用存在,垃圾回收器就不会回收该对象。
软引用:用于描述还有用,但非必须的对象,内存够,不回收,内存不足则回收,用于实现内存敏感的高速缓存,软引用可以和引用队列ReferceQueue联合使用,如果软引用被垃圾回收器回收,JVM就会把他加入关联的引用队列中
弱引用:与软引用大致相同,区别在于只具有弱引用的对象拥有更短暂的生命周期,垃圾回收器一但发现了只具有软引用的对象,不管内存够不够,都会回收。
虚引用:形同虚设,不决定对象的生命周期,如果对象只有虚引用,那么和没有任何引用一样,任何时候都能被垃圾回收器回收,虚引用主要用来跟踪对象被垃圾回收器回收的活动
虚引用与软引用的区别:虚引用必须与引用队列联合使用,垃圾回收器回收对象时若发现存在虚引用,则会先把虚引用加入相关联的引用队列中
StringBuffer、String、SpringBuilder
适用场景:String适用于少量字符串操作的情况,StringBuffer适用于多线程下在字符缓冲区进行大量操作的情况,StringBuilder适用于单线程在字符缓冲区进行大量操作的情况
运行速度:StringBuilder>StringBuffer>String String最慢的原因是因为String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的
线程安全:StringBuilder中有很多方法都可以带有Snchronized关键字,所以可以保证线程是安全的,StringBuilder的方法没有Snchronized关键字,不能保证线程安全,有可能出现一些错误操作
This关键字
指针,指向当前对象的引用
public class userDemo {
public void run(){
new userTemp(this);
}
public static void main(String[] args){
new userDemo().run();
}
}
class userTemp{
public userTemp(userDemo demo) {
System.out.println("IM userDemo");
}
}
注:java中为什么在static中不能使用this关键字?
Static方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。而this指代的是当前的对象
在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.
而且,更为重要的是this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,
则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.
super关键字
指针,指向直接父类对象的引用
public class userDemo {
String str="123";
public void info(){
System.out.println("userDemo info");
}
public static void main(String[] args){
new userTemp().mation();
}
}
class userTemp extends userDemo{
String str="321";
public userTemp() {
// super.info();
}
public void info(){
System.out.println("userTemp info");
}
public void mation(){
System.out.println("str="+str);
System.out.println("super.str="+super.str);
System.out.println(new userDemo().str);
}
}
调用父类构造函数:super()
调用父类全局变量:super.变量名
调用父类方法:super.方法名
注:Super不能出现在static修饰的方法中
static关键字
1、被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来。
2、被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来。
被static修饰的变量、被static修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。JDK把不同的静态资源放在了不同的类中而不把所有静态资源放在一个类里面,很多人可能想当然认为当然要这么做,但是是否想过为什么要这么做呢?个人认为主要有三个好处:
1、不同的类有自己的静态资源,这可以实现静态资源分类。比如和数学相关的静态资源放在java.lang.Math中,和日历相关的静态资源放在java.util.Calendar中,这样就很清晰了。
2、避免重名。不同的类之间有重名的静态变量名、静态方法名也是很正常的,如果所有的都放在一起不可避免的一个问题就是名字重复,这时候怎么办?分类放置就好了。
3、避免静态资源类无限膨胀,这很好理解。
静态资源属于类,但是是独立于类存在的。从JVM的类加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类new的时候加载的。类的初始化早于类的new,比如Class.forName(“xxx”)方法,就是初始化了一个类,但是并没有new它,只是加载这个类的静态资源罢了。所以对于静态资源来说,它是不可能知道一个类中有哪些非静态资源的;但是对于非静态资源来说就不一样了,由于它是new出来之后产生的,因此属于类的这些东西它都能认识。所以上面的几个问题答案就很明确了:
1、静态方法能不能引用非静态资源?不能,new的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。
2、静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。
3、非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是new之后才产生的,那么属于类的内容它都认识。
静态代码块是严格按照父类静态代码块->子类静态代码块的顺序加载的,且只加载一次。
static修饰类
这个用得相对比前面的用法少多了,static一般情况下来说是不可以修饰类的,如果static要修饰一个类,说明这个类是一个静态内部类(注意static只能修饰一个内部类),也就是匿名内部类。像线程池ThreadPoolExecutor中的四种拒绝机制CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。
final关键字
1、被final修饰的类不可以被继承
2、被final修饰的方法不可以被重写
3、被final修饰的变量值可以被改变,但是指向的内容不可以被改变
复写与重载
重载:方法名相同,参数列表不同(个数、顺序、类型不同)与返回类型无关。
重写 :覆盖。 将父类的方法覆盖。 重写方法重写:方法名相同,访问修饰符只能大于被重写的方法访问修饰符,方法签名个数,顺序个数类型相同。
Override(重写)
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为final不能被重写。
Overload(重载)
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于父类和子类、同类中。
而重载的规则
1、必须具有不同的参数列表。 2、可以有不同的返回类型,只要参数列表不同就可以了。 3、可以有不同的访问修饰符。 4、可以抛出不同的异常。
重写方法的规则
1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。 2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。 3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)。 4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。
例如: 父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
接口跟抽象的区别
Interface 只能有成员常量,只能是方法的声明。 Abstract class可以有成员变量,可以声明普通方法和抽象方法。
interface是接口,所有的方法都是抽象方法,成员变量是默认的public static final 类型。接口不能实例化自己。
abstract class是抽象类,至少包含一个抽象方法的累叫抽象类,抽象类不能被自身实例化,并用abstract关键字来修饰。