继承
- 语法:
[访问权限] class 子类名 extends 父类名{
类体定义;
}
继承一个父类,只能继承非私有的数据 - protected–受保护的访问权限修饰符,用protected修饰的属性和方法可以被子类继承
- 构造方法不能被继承
==创建子类对象时(无论是默认的还是带参数的),父类的构造方法也会被调用(因为子类要使用到父类的数据,就要通过父类的构造方法来初始化数据)==(调用不是继承)
调用该构造方法不一定就是创建该对象 - 当父类中没有无参构造方法时,子类必须显示的调用父类的带参构造方法。可以在子类中显示的使用super(…)调用父类的构造方法,只能出现在第一句;子类有参的构造方法中要显示的使用super(…)
- 在子类进行实例化操作的时候,首先会先让其父类进行初始化操作,之后子类再自己进行实例化操作
- 在子类和父类中,重写方法后,在调用时,以创建的对象类型为准,会调用谁的方法
- 方法重载:发生在同一个类中,方法名相同,参数列表不同,返回值无关
方法重写:发生在子父类中,方法名相同,参数列表相同,返回值相同,子类的访问修饰符要大于或等于父类的访问修饰符,子类的异常声明必须要小于或等于父类的异常声明。如果方法被private,static,final修饰,那么不能被重写 - super.属性表示调用父类的属性,如果是继承过来的属性,super可以省略
super.方法调用父类的方法(可在方法重写里) - this表示当前对象
使用super来调用父类的属性、方法和构造方法 - 比较两个字符串的值是否相等,不能使用==,使用equals()
- final关键字:
- 声明一个常量(系统不会给其赋默认值):
修饰属性或局部变量(最终变量),也称为常量,常量必须在定义时或在构造器中初始化 - 声明一个方法:
该方法为最终方法,且只能被子类继承,但是不能被子类重写 - 声明一个类(通常在常量类中使用):
该类就转变为最终类,没有子类的类,final修饰的类无法被继承 - 在方法参数中使用final,在该方法内部不能修改参数的值
- 声明一个常量(系统不会给其赋默认值):
final static变量为什么要初始化
- 在java中用final修饰符修饰的变量表示不可以被二次赋值,且系统不会给其赋默认值。
如果单纯只是final变量,可以在定义的时候就赋默认值,也可以在构造方法中赋默认值。
但是如果同时用final static 修饰变量,因为static变量属于类而不属于对象,且在调用构造方法之前static 变量就已经被系统给赋默认值。而相应的final static 变量就只能在定义的时候就初始化,否则既无法在构造方法中初始化,系统又不会赋默认值,相当于这个变量被定义出来是毫无用处的。 因此java中final static变量必须初始化。
注:类的属性会被赋予默认值,也就是那些定义在类内部、方法外部的变量,不管是不是static,都会被赋值
抽象类(里面可以没有抽象方法)
- 很多具有相同特征和行为的对象可以抽象为一个类;很多具有相同特征和行为的类可以抽象为一个抽象类;使用abstract关键字声明的类为抽象类
- 抽象类里面不一定是抽象方法(只有声明,没有实现),也可以有可以实现的方法;
- 继承抽象类的具体类必须实现所有抽象方法 抽象类不能被实例化(new()出来一个对象)
接口
- 接口(可看做合同、规则,需要人去实现,但它没有实现(JDK1.8后默认方法可以实现))的定义格式:
interface 接口名称{
全局常量;
==抽象方法==;(没有属性)
}
注:接口不是类,接口是可以继承的(需要被一个具体的类去实现) - 接口中定义的方法没有声明修饰符,默认为public abstract;变量默认为public、abstract
- 接口之间可以多继承(注意:类是只能单继承,只有接口才能继承接口)
- 实现类–实现接口的类,不是继承,可实现多个接口(类名 implements 接口名)
- 具体类实现接口必须实现接口的所有方法
- 抽象类实现接口可以不实现接口的方法
- 接口不能有构造方法
- 在接口中定义的方法没有声明访问修饰符,默认为public
- 接口不能被实例化
- Lambda表达式:(函数式接口)
语法:(参数1,参数2…)->{…}//具有一个方法
注:不会单独生成class文件,若有final,必须带上类型 - default关键字可以让接口中的方法可以有默认的函数体,当一个类实现这个接口时,可以不用去实现这个方法,当然,这个类若实现这个方法,就等于子类覆盖了这个方法。
- JDK8以后允许我们在接口中定义static方法和default方法。
- 静态方法,只能通过接口名调用,不可以通过实现类的类名或者实现类的对象调用。default方法,只能通过接口实现类的对象来调用。
- 如果多个接口中存在同样的static和default方法会怎么样呢?
如果有两个接口中的静态方法一模一样,并且一个实现类同时实现了这两个接口,此时并不会产生错误,因为jdk8只能通过接口类调用接口中的静态方法,所以对编译器来说是可以区分的。但是如果两个接口中定义了一模一样的默认方法,并且一个实现类同时实现了这两个接口,那么必须在实现类中重写默认方法,否则编译失败。
接口和抽象类设计理念的区别
- 抽象类:被继承体现的是:”is a”的关系,抽象类中定义的是该继承体系的共性功能
- 接口:被实现体现的是:”like a”的关系,接口中定义的是该继承体系的扩展功能
面向对象设计原则:
- 对修改关闭,对扩展开放
- 面向接口编程
多态
- 多态性:对象在运行过程中多种形态
- 多态性我们大概可以分为两类:
- 方法的重载与重写(方法多态性)
- 对象的多态性
- 用父类的引用指向子类对象(用大的类型去接受小的类型,向上转型、自动转换)//类型转换(执行的是子类的方法)
- 父类通常都定义为抽象类、接口
- 向上转型:格式:
父类 父类对象=子类实例;(自动转换) - 向下转型:格式:
子类 子类对象=(子类)父类实例(强制转换)==将父类实例转换为子类实例== - instanceof是用来检查对象是否为指定的类型,通常在把父类的实例强制转换为子类引用时要使用,以避免发生类型转换异常 java.lang.ClassCastException(需要在转换之前作类型检查)
语法格式:对象 instanceof 类型 –返回boolean类型值(该语句一般用于判断一个对象是否为某个类的实例 - 抽象类应用–模板方法模式:定义一个操作中的算法的骨架,而将一些可变部分的实现延迟到子类中,模板方法模式使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤
- 接口类应用–策略模式:定义了一系列的算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于使用它的客户应用而独立变化(把可变的东西拿出来封装)
Object类
- Object类是类层次结构的根类
- 每个类都使用Object作为超类,所有对象(包括数组)都实现这个类的方法
- 所有类都是Object类的子类
toString()方法
- public String toString()方法
返回该对象的字符串表示
不重写返回值:
return(getClass().getName()(类的名字)+”@”+Integer.toHexString(hashCode()));
通常,toString方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明且易于读懂的信息表达式。建议所有子类都重写此方法(直接写对象的名称也可调用此方法)
当遍历数组的时候,输出的对象名就是调用此方法
equals
- public boolean equals(Object obj)
return (this==obj) (比较地址)
指示其他某个对象是否与此对象“相等”。equals方法在非空对象引用上实现相等关系:
自反性 对称性 传递性 一致性
字符串类里重写了equals方法,使得两个属性一样的对象返回true - protected void finalize()throws Throwable 回收垃圾
- public final Class
hashCode()
- public int hashCode();返回该对象的哈希码值;注意:哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但不是实际地址值,可以理解为地址值
clone
- protected void clone();创建并返回此对象的一个副本(需要重写该方法)
适配器设计模式
当两个不同接口的电源要连接到同一个接口时,我们需要通过一个适配器实现A接口,并且把B接口作为属性从而使B电源可以插进A接口
//适配器设计模式(两个不同接口的电源要连接到同一个接口)
public class Test7 {
public static void main(String[] args){
PowerA powerA=new PowerAImpl();
work(powerA);
PowerB powerB=new PowerBImpl();
Adapter adapter=new Adapter(powerB);
work(adapter);
}
public static void work(PowerA a){
System.out.println("正在连接...");
a.insert();
System.out.println("工作结束");
}
}
interface PowerA{
public void insert();
}
interface PowerB{
public void connet();
}
//适配器
class Adapter implements PowerA{
private PowerB powerB;
public Adapter(PowerB powerB){
this.powerB=powerB;
}
public void insert(){
powerB.connet();
}
}
class PowerAImpl implements PowerA{
public void insert(){
System.out.println("电源A开始工作");
}
}
class PowerBImpl implements PowerB{
public void connet(){
System.out.println("电源B开始工作");
}
}
内部类
- 成员内部类和方法内部类可以访问外部类的属性
- 成员内部类格式如下(依赖于对象):
class Outer{
class Inner{ }
} - //在外部创建成员内部类的实例,因为成员内部类需要依赖外部类的对象
//通常情况下,不建议这样来实例化内部类的对象
Outer outer=new Outer();
Outer.Inner inner=outer.new Inner();
建议在外部类中定义一个方法,对外提供访问内部类的接口 - 方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化
- 方法内部类对象不能使用该内部类所在方法的非final局部变量
- [x] 原因:当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法被调用时会入栈,方法结束后即弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,显然无法使用,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也就可以继续使用(在jdk1.8中取消了这个特性)
- 静态内部类(优先考虑使用)
- 静态嵌套类仅能访问外部类的静态成员和方法
Outer.Inner inner=new Outer.Inner()//不依赖对象 - 匿名内部类
三种情况:
(1)继承式的匿名内部类
(2)接口式的匿名内部类
(3)参数式的匿名内部类
注:匿名内部类编译系统给其以1,2,3…等数字编号