类
数据类型
- 类变量(静态变量或静态成员变量):类型本身具有的属性, static修饰
- 类方法 (静态方法):类型本身可以进行的操作,static修饰
- 实例变量:类型实例具有的属性,每个实例都可以有不同值
- 实例方法:类型实例可以进行的操作
static不允许用来修饰局部变量
public class BigDecimal extends Number implements Comparable<BigDecimal> {
// 实例变量
private final int scale;
// 类变量
public static final BigDecimal ZERO =
zeroThroughTen[0];
// 实例方法
public BigDecimal abs(MathContext mc) {
return (signum() < 0 ? negate(mc) : plus(mc));
}
// 类方法
private static long add(long xs, long ys){
long sum = xs + ys;
if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) { // not overflowed
return sum;
}
return INFLATED;
}
}
复制代码
成员变量:类变量和实例变量
成员方法:类方法和实例方法
注意:
- 实例变量和实例方法只能通过实例(对象)来访问
- 类方法只能访问类变量不能访问实例变量,只能调用类方法不能调用实例方法
- 实例方法既能访问类变量又能访问实例变量,既能调用类方法又能调用实例方法
对象和数组有两块内存:一块存放实际内容,一块存放实际内容的位置
静态初始化代码块(只会在类加载时被执行一次)
非静态代码块
构造方法
特点
- 名称固定,与类名相同
- 没有返回值,也不能有返回值。隐含的返回值为实例本身
- 可以重载
- 子类通过super调用父类的构造方法,没有显示调用会自动调用父类默认的构造方法
this用法
- 表示当前实例
- 在构造方法中调用其他构造方法,必须放在方法第一行
默认构造方法
- 每个类至少有一个构造方法,编译器自动生成
- 如果定义了构造方法则不会再生成
私有构造方法(private 修饰)使用场景
- 不能创建类的实例,类只能被静态访问
- 能创建类的实例,但只能类的静态方法调用(单例模式)
- 被其他构造方法调用
public class BigDecimal extends Number implements Comparable<BigDecimal> {
public BigDecimal(BigInteger val) {
scale = 0;
intVal = val;
intCompact = compactValFor(val);
}
// 重载构造方法
public BigDecimal(BigInteger val, MathContext mc) {
// this 调用其他构造方法
this(val,0,mc);
}
}
复制代码
new 操作即创建对象
分配内存(包括本类和父类所有的实例变量,不包括静态变量)
给实例变量设置默认值
执行实例初始化代码(定义实例变量是的赋值语句、非静态代码块和构造方法)
复制代码
类加载时内部成员加载顺序
public class A {
public A(String className){
System.out.println("静态变量:"+className);
}
}
public class B {
public B(String className){
System.out.println("实例变量:"+className);
}
}
public class Base {
private B baseB = new B("父类");
private static A baseA = new A("父类");
static{
System.out.println("父类静态代码块");
}
{
System.out.println("父类非静态代码块");
}
public Base(){
System.out.println("父类构造方法");
}
}
public class Test extends Base {
private B baseB = new B("子类");
private static A baseA = new A("子类");
{
System.out.println("子类非静态代码块");
}
static{
System.out.println("子类静态代码块");
}
public Test(){
System.out.println("子类构造方法");
}
public static void main(String[] args) {
new Test();
}
}
静态变量:父类
父类静态代码块
静态变量:子类
子类静态代码块
实例变量:父类
父类非静态代码块
父类构造方法
实例变量:子类
子类非静态代码块
子类构造方法
// 变换静态代码块和静态变量的顺序
// 变换非静态代码块和实例变量的顺序
public class Base {
public Base(){
System.out.println("父类构造方法");
}
static{
System.out.println("父类静态代码块");
}
{
System.out.println("父类非静态代码块");
}
private B baseB = new B("父类");
private static A baseA = new A("父类");
}
public class Test extends Base {
public Test(){
System.out.println("子类构造方法");
}
{
System.out.println("子类非静态代码块");
}
static{
System.out.println("子类静态代码块");
}
private B baseB = new B("子类");
private static A baseA = new A("子类");
public static void main(String[] args) {
new Test();
}
}
父类静态代码块
静态变量:父类
子类静态代码块
静态变量:子类
父类非静态代码块
实例变量:父类
父类构造方法
子类非静态代码块
实例变量:子类
子类构造方法
复制代码
1、 首先执行Test的入口方法main方法,但在执行main方法前需要先加载Test类,加载Test类时发现Test类继承自Base类,所以要先加载Base类。
2、 加载Base类时,要执行类成员赋值--类变量初始化和静态代码块初始化(具体顺序根据定义的顺序来),加载完Base类后接着加载Test类,执行类变量初始化和静态代码块初始化
3、 类加载完成后开始执行main方法,执行new Test()方法。Test类有父类所以先执行父类的操作,实例成员赋值--实例变量初始化和非静态代码块初始化(具体顺序根据定义的顺序来),调用Base的构造方法,然后执行Test的操,作实例变量初始化和非静态代码块初始化(具体顺序根据定义的顺序来),调用Test的构造方法
执行顺序总结
1、 父类静态成员 2、 子类静态成员 3、 父类实例成员 4、 父类构造方法 5、 子类实例成员 6、 子类构造方法
- 静态代码块和静态变量执行的顺序根据定义的先后顺序
- 非静态代码块和实例变量的顺序执行的顺序根据定义的先后顺序
每个类封装器内部细节,对外提供更高层次的功能,使其他类在更高层次上考虑和解决问题,是程序设计的一种基本思维方式。
继承
特点
- 代码复用,公共的属性和方法放在父类而子类只关注子类特有的功能
- 统一处理不同的子类对象
如果一个类没有声明父类,会有一个隐含的父类Object
一个类最多只能继承一个父类
子类不能访问父类私有的方法和属性,继承私有外的方法和属性
super 关键字
super用于指代父类,可以调用父类的构造方法,访问父类的方法和变量
this引用一个真实的对象,可以作为函数参数和返回值,但super只是一个关键字,不能作为参数和返回值
复制代码
重写和重载
重写
发生在父类与子类之间
可以加@Override注解
子类重新定义父类中的同名且参数签名相同的方法
复制代码
重载
发生在同一类中
重载是指方法名相同但参数签名不同(参数个数、顺序、类型)
复制代码
当有多个重名函数的时候,在决定调用哪个函数的过程中,首先按照参数的类型进行匹配,寻找素有重载方法中最匹配的,然后才看变量的动态类型,进行动态绑定
向上转型
子类对象赋值给父类应用变量,转型就是转换类型,向上转型就是转换成父类类型
Child child = new Child();
Base base = child; // 向上转型
复制代码
多态
多态指子类对象可以赋值给父类应用变量
一种类型的变量可以引用多种实际子类型的变量
静态类型指声明的类型,动态类型指引用的类型
// 类型Base 称为 base 的静态类型,child1、child2 称为base的动态类型
Child child1 = new Child();
Child child2 = new Child();
Base base = child1;
Base base = child2;
复制代码
动态绑定
动态绑定指调用方法是调用的是动态类型(子类)的方法
需运行时才能确认
复制代码
静态绑定
静态绑定指访问绑定到变量的静态类型
编译阶段即可确认
实例变量、静态变量、静态方法和private方法都是静态绑定
复制代码
一个父类的变量能不能转换成子类的变量,取决于父类变量的动态类型是不是这个子类或子类的子类
instanceof 关键字判定一个引用是不是指定类型
封装就是隐藏实现细节,提供简化接口
继承可能破坏封装,因为子类和父类之间可能存在着实现细节的依赖
优先使用组合和接口
抽象类
- 定义了抽象方法的类必须声明为抽象类
- 抽象类可以有非抽象的方法
- 抽象类可以定义实例变量
接口
- 接口中的方法的默认修饰符 public abstract
- 接口中的变量的默认修饰符 public static final
- 接口可以多继承,类可以实现多个接口
- 可以用instanceof 关键字判断一个对象是否实现某个接口
- 使用接口和组合代替继承既可以统一处理又可以服用代码
- 接口中可以有静态方法和默认方法
public interface List<E> extends Collection<E> {
}
复制代码
针对接口编程可以复用代码,降低耦合,提高灵活性
抽象类和接口对比
- 抽象类和接口都不能用于创建对象
- 接口只能定义静态变量不能定义实例变量,抽象类可以定义实例变量和静态变量
- 一个类可以实现多个接口,只能继承一个类
- 接口声明能力,抽象类提供默认实现。可以配合使用。