重写equals(Object类提供的equals()方法只有引用变量指向同一个对象时才能返回true,因此我们需要吃重写equals方法)
//如在Person类中重写equals方法
public boolean equals(Object obj){
//如果两个对象为同一对象
if(this==obj){
return true;
}
//只有obj是Person对象
if(obj!=null && obj.getClass() == Person.class){
Person personObj = (Person)obj;
//并且当前对象的idStr与obj对象的idStr相等时才可判断两对象相等
if(this.getIdStr().equals(personObj.getIdStr)){
return true;
}
}
return false;
}
重写equals()满足
自反性:对任意x,x.equals(x)一定返回true
对称性:对任意x,y,如果y.equals(x)返回true,则x.equals(y)也返回true
传递性:对任意x,y,z,如果x.equals(y)返回true,则y.equals(z)也返回true,那么x.equals(z)一定返回true
一致性:对任意x和y,如果对象中用于等价的比较信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。
对于任何不适null的x,x.equals(null)一定返回false
Object默认提供的equals()只是比较对象的地址,即Object类的equals()方法比较的结果与==运算符比较的结果完全相同。因此实际应用中常常要重写equals();
- 对static关键字而言,有一条非常重要的规则:类成员(包括方法、初始化块、内部类和枚举类)不能访问实例成员(包括成员变量、方法、初始化块、内部类和枚举类)。因为类成员时属于类的,类成员的作用域比实例成员的作用域更大,完全可能出现类成员已经初始化完成,但实例成员还不曾初始化的情况,如果允许类程艳访问实例对象会将引起大量错误。
如果一个类始终只能创建一个实例,则这个类被称为单例类(Singleton)
class Singleton{
//使用一个类变量来缓存曾创建的实例
private static Singleton instance;
//对构造器使用private修饰,隐藏该构造器
private Singleton(){}
//提供一个静态方法,用于返回Singleton实例
//该方法可以加入自定义控制,保证只产生一个Singleton对象
public static Singleton getInstance(){
//如果instance为null,则表明还不曾创建Sinleton对象
//!=null则不创建新的实例
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
public class SingletonTest{
public static void main(String[] args){
//创建Singleton对象不能通过构造器,只能同过getInstance()方法来获取
Singleton s1 = Singleton.getInstance();
Singleton s1 = Singleton.getInstance();
System.out.println(s1 ==s2);
}
final关键字修饰的成员变量必须由程序员显示地执行初始值
- 与普通成员不同的是,final成员变量(包括实例变量和类变量)必须由程序员显示初始化,系统不会队final成员进行隐式初始化。
- final修饰符的一个重要途径就是定义“宏变量”,当定义final变量时就为该变量指定了初始值,而且该初始值可以在编译时就确定下来,那么这个fnal变量的本质就是“宏变量”,编译器会把程序中所有用到的地方直接替换成该变量的值。
- Java会使用常量池来管理曾经用过的字符串直接量,例如执行String a =
“Java”,语句之后,常量池中就会缓存一个字符串”java”,如果程序再次执行String b =
“java”,系统将会让b直接指向常量池中的”java”字符串,因此a =b将会返回true。 - final修饰的方法不能被重载,但是可以被重写
final:修饰的已初始化的变量不可再赋值
修饰的方法不可被重写(如Object类中的getClass())
修饰的类不可有子类(如java.lang.Math)
不可变类:创建该类的实例后,该实例的实例变量是不可改变的,Java提供的8个包装类和java.lang.String类都是不可变类
例如:Double d = new Double(6.5);
String str = new String(“Hello”)
抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。
规则如下:
1.抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract
修饰符来修饰,抽象方法不能有方法体。
2.抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽
象类的实例。即使抽象类里没有抽象方法,这个抽象类也不能创建实例。
3.抽象类可以包含成员变量、方法、构造器、初始化块、内部类(接口和枚
举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类
调用
含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类
归纳起来,抽象类可用“有得有失”4个字来描述,“得”指的是抽象类多了一个能力:抽象类可以包含抽象方法;“失”:指的是抽象类失去了一个能力:抽象类不能用于创建实例。
定义抽象方法只需要在普通方法上增加abstract修饰符,并把普通方法的方法体全部去掉,并在方法后增加分号即可。
利用抽象类和抽象方法的优势,可以更好的发挥多态的优势,使得程序更加灵活。final关键字修饰的类不可被继承,因此abstract类和final不可能同时出现。(static也不能)。
抽象类是希望被子类利用的,所以private不可能修饰该类
模板模式的简单规则:
抽象父类可以只定义需要使用的某些方法,把不能实现的部分抽象成抽
象方法,留给其子类实现类实现,也可以由其子类实现。父类里提供的方法
只是定义了 一个通用算法,其实现也许并不完全由自身实现,而必须依赖其
子类的 辅助。
特殊的“抽象类”-----接口(interface),接口中不能包含普通方法,接口里的所有方法都是抽象方法。Java8对接口进行了改进,允许在接口中定义默认方法,默认方法可以提供方法实现。
Java8中接口的定义
和类不同,定义接口不在使用class关键字,而是使用interface关键字。接口定义的基本语法如下:
[修饰符] interface 接口名 extends 父接口1 父接口2
public abstract class SpeedMeter{
//转速
private double turnRate;
public SpeedMeter(){
}
//把返回车轮半径的方法定义成抽象方法
public abstract double getRadius();
public void setTurnRate(double turnRate){
this.turnRate = turnRate;
}
//定义计算速度的通用算法
public double getSpeed(){
//速度等于 车轮半径*2*PI*getRadius()*turnRate;
}
}
public class CarSpeedMeter extends SpeedMeter{
public double getRadius(){
return 0.28;
}
public static void main(String[] args){
CarSpeedMeter csm = new CarSpeedMeter();
csm.setTurnRate(15);
System.out.println(scm.getSpeed());
}
}