接口的意义
接口的意义用三个词就可以概括:规范,扩展,回调。
抽象类的意义
抽象类的意义可以用三句话来概括:
1.为其他子类提供一个公共的类型
2.封装子类中重复定义的内容
3.定义抽象方法,子类虽然有不同的实现,但是定义时一致
https://blog.csdn.net/Sterry_Gong/article/details/90812773 形象说明这个
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。
1.名字与类名相同;
2.没有返回值,但不能用void声明构造函数;
3.生成类的对象时自动执行,无需调用。
构造器是一个特殊的方法,可以有访问性质的修饰,但是不能够被abstract,final,native,static,synchronized修饰
构造器不能被继承,所以不能重写,但是可以重载
帮助子类做初始化工作。
Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
为什么非法
由于静态方法可以不通过对象进行调用,类的静态成员(变量和方法)属于类本身,在类加载的时候就会分配内存,可以通过类名直接去访问;非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。
有何不同
在一个类的静态成员中去访问其非静态成员之所以会出错是
因为在类的非静态成员不存在的时候类的静态成员就已经存在了,访问一个内存中不存在的东西当然会出错:
static
修饰的,那么这个成员变量是属于类的,如果没有使用static
修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。
1.采用new(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)
2.通过反射
3.采用clone
4.通过序列化机制
前2者都需要显式地调用构造方法。造成耦合性最高的恰好是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用。
1.equals()
2.clone()
3.getClass()
4.notify(),notifyAll(),wait()
5.toString()
6.finalize()
1.强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,
使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
如obj.equels(new Object());而这样 obj对象对后面new Object的一个强引用,只有当obj这个引用被释放之后,对象才会被释放
2.软引用(SoftReference):在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,
只有在内存不足时,软引用才会被垃圾回收器回收。
3.弱引用(WeakReference):具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,
无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。
4.虚引用(PhantomReference):顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。
这点在四种引用类型中已经做了解释,这里简单说明一下即可:
虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率,但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,
而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。
不像C语言,我们可以控制内存的申请和释放,在Java中有时候我们需要适当的控制对象被回收的时机,因此就诞生了不同的引用类型,
可以说不同的引用类型实则是对GC回收时机不可控的妥协。有以下几个使用场景可以充分的说明:
1.利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,
JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题.
2.通过软引用实现Java对象的高速缓存:比如我们创建了一Person的类,如果每次需要查询一个人的信息,哪怕是几秒中之前刚刚查询过的,
都要重新构建一个实例,这将引起大量Person对象的消耗,并且由于这些对象的生命周期相对较短,会引起多次GC影响性能。
此时,通过软引用和 HashMap 的结合可以构建高速缓存,提供性能。
对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们指向的内存地址是否相等。
方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!
可变性
简单的来说:String 类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是不可变的。
而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串char[]value
但是没有用 final 关键字修饰,所以这两种对象都是可变的
线程安全性
String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,
定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,
所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,
而不是生成新的对象并改变对象引用。相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结
1.操作少量的数据= String
2.单线程操作字符串缓冲区下操作大量数据= StringBuilder
3.多线程操作字符串缓冲区下操作大量数据= StringBuiffer
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型“= =”比较的是值,
引用数据类型 = = 比较的是内存地址).
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
说明:
String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,
而 String 的 equals 方法比较的是对象的值。
当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,
如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。
面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”
hashCode()介绍
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)。
为什么要有 hashCode
我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head fist java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
hashCode()与equals()的相关规定
1.如果两个对象相等,则hashcode一定也是相同的。
2.两个对象相等,对两个对象分别调用equals方法都返回true。
3.两个对象有相同的hashcode值,它们也不一定是相等的。
4.因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖,hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),
则该 class 的两个对象无论如何都不会相等。
原文:https://www.cnblogs.com/sqzrlqq/p/13047128.html