static
1.静态变量
- 静态变量:又称为类变量,类所有的实例都共享静态变量,也可以直接通过类名来访问静态变量,静态变量在内存中只存在一份。
 - 实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
注意:有static的: 用类名去调 (注意:静态不会空指针。) 没有static的: 先new对象用引用去调。
- 存储位置
- 静态变量存储在方法区中的静态区。
 - 实例变量存储在堆内存。
 - 局部变量储存在栈内存。
 
 
 - 存储位置
 
public class A {private int x; // 实例变量private static int y; // 静态变量public static void main(String[] args) {// int x = A.x; // Non-static field 'x' cannot be referenced from a static contextA a = new A();int x = a.x;int y = A.y;}}
2.静态方法
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
public abstract class A {public static void func1(){}// public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'}
只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字,因为这两个关键字与具体对象关联。
public class A {private static int x;private int y;public static void func1(){int a = x;// int b = y; // Non-static field 'y' cannot be referenced from a static context// int b = this.y; // 'A.this' cannot be referenced from a static context}}
3. 静态语句块
静态语句块在类初始化时运行一次。
public class A {static {System.out.println("123");}public static void main(String[] args) {A a1 = new A();A a2 = new A();}}
4.静态内部类
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。
public class OuterClass {class InnerClass {}static class StaticInnerClass {}public static void main(String[] args) {// InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static contextOuterClass outerClass = new OuterClass();InnerClass innerClass = outerClass.new InnerClass();StaticInnerClass staticInnerClass = new StaticInnerClass();}}
静态内部类不能访问外部类的非静态的变量和方法。
5. 静态导包
在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。
import static com.xxx.ClassName.*
6. 初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
public static String staticField = "静态变量";
static {System.out.println("静态语句块");}
public String field = "实例变量";
{System.out.println("普通语句块");}
最后才是构造函数的初始化。
public InitialOrderTest() {System.out.println("构造函数");}
存在继承的情况下,初始化顺序为:
- 父类(静态变量、静态语句块)
 - 子类(静态变量、静态语句块)
 - 父类(实例变量、普通语句块)
 - 父类(构造函数)
 - 子类(实例变量、普通语句块)
 - 
继承
1.案例
1.1 案例代码实现
1.父类Human类
public class Human {// 合理隐藏private String name ;private int age ;// 合理暴露public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
2.子类Teacher类
 
public class Teacher extends Human {// 工资private double salary ;// 特有方法public void teach(){System.out.println("老师在认真教技术!");}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}}
3.子类Student类
public class Student extends Human{}
4.子类BanZhuren类
public class Teacher extends Human {// 工资private double salary ;// 特有方法public void admin(){System.out.println("班主任强调纪律问题!");}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}}
5.测试类
public class Test {public static void main(String[] args) {Teacher dlei = new Teacher();dlei.setName("播仔");dlei.setAge("31");dlei.setSalary(1000.99);System.out.println(dlei.getName());System.out.println(dlei.getAge());System.out.println(dlei.getSalary());dlei.teach();BanZhuRen linTao = new BanZhuRen();linTao.setName("灵涛");linTao.setAge("28");linTao.setSalary(1000.99);System.out.println(linTao.getName());System.out.println(linTao.getAge());System.out.println(linTao.getSalary());linTao.admin();Student xugan = new Student();xugan.setName("播仔");xugan.setAge("31");//xugan.setSalary(1000.99); // xugan没有薪水属性,报错!System.out.println(xugan.getName());System.out.println(xugan.getAge());}}
1.2小结
1.继承实际上是子类相同的属性和行为可以定义在父类中,子类特有的属性和行为由自己定义,这样就实现了相同属性和行为的重复利用,从而提高了代码复用。
2.子类继承父类,就可以直接得到父类的成员变量和方法。是否可以继承所有成分呢?请看下节!
2.子类不能继承的内容
子类不能继承父类的构造方法。
值得注意的是子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已,可以通过getter/setter方法访问父类的private成员变量。
public class Demo03 {public static void main(String[] args) {Zi z = new Zi();System.out.println(z.num1);// System.out.println(z.num2); // 私有的子类无法使用// 通过getter/setter方法访问父类的private成员变量System.out.println(z.getNum2());z.show1();// z.show2(); // 私有的子类无法使用}}class Fu {public int num1 = 10;private int num2 = 20;public void show1() {System.out.println("show1");}private void show2() {System.out.println("show2");}public int getNum2() {return num2;}public void setNum2(int num2) {this.num2 = num2;}}class Zi extends Fu {}
3.继承后的特点—成员变量
成员变量不重名
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码如下:
class Fu {// Fu中的成员变量int num = 5;}class Zi extends Fu {// Zi中的成员变量int num2 = 6;// Zi中的成员方法public void show() {// 访问父类中的numSystem.out.println("Fu num="+num); // 继承而来,所以直接访问。// 访问子类中的num2System.out.println("Zi num2="+num2);}}class Demo04 {public static void main(String[] args) {// 创建子类对象Zi z = new Zi();// 调用子类中的show方法z.show();}}演示结果:Fu num = 5Zi num2 = 6
成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的。代码如下:
class Fu1 {// Fu中的成员变量。int num = 5;}class Zi1 extends Fu1 {// Zi中的成员变量int num = 6;public void show() {// 访问父类中的numSystem.out.println("Fu num=" + num);// 访问子类中的numSystem.out.println("Zi num=" + num);}}class Demo04 {public static void main(String[] args) {// 创建子类对象Zi1 z = new Zi1();// 调用子类中的show方法z1.show();}}演示结果:Fu num = 6Zi num = 6
子父类中出现了同名的成员变量时,子类会优先访问自己对象中的成员变量。如果此时想访问父类成员变量如何解决呢?我们可以使用super关键字。
super访问父类成员变量
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super 关键字,修饰父类成员变量,类似于之前学过的 this 。
需要注意的是:super代表的是父类对象的引用,this代表的是当前对象的引用。
使用格式:
super.父类成员变量名
class Fu {// Fu中的成员变量。int num = 5;}class Zi extends Fu {// Zi中的成员变量int num = 6;public void show() {int num = 1;// 访问方法中的numSystem.out.println("method num=" + num);// 访问子类中的numSystem.out.println("Zi num=" + this.num);// 访问父类中的numSystem.out.println("Fu num=" + super.num);}}class Demo04 {public static void main(String[] args) {// 创建子类对象Zi1 z = new Zi1();// 调用子类中的show方法z1.show();}}演示结果:method num=1Zi num=6Fu num=5
小贴士:Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
4.继承后的特点—成员方法
成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
class Fu {public void show() {System.out.println("Fu类中的show方法执行");}}class Zi extends Fu {public void show2() {System.out.println("Zi类中的show2方法执行");}}public class Demo05 {public static void main(String[] args) {Zi z = new Zi();//子类中没有show方法,但是可以找到父类方法去执行z.show();z.show2();}}
成员方法重名
如果子类父类中出现重名的成员方法,则创建子类对象调用该方法的时候,子类对象会优先调用自己的方法。
class Fu {public void show() {System.out.println("Fu show");}}class Zi extends Fu {//子类重写了父类的show方法public void show() {System.out.println("Zi show");}}public class ExtendsDemo05{public static void main(String[] args) {Zi z = new Zi();// 子类中有show方法,只执行重写后的show方法z.show(); // Zi show}}
5.方法重写
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
为了满足里式替换原则,重写有以下三个限制:
- 子类方法的访问权限必须大于等于父类方法;
 - 子类方法的返回类型必须是父类方法返回类型或为其子类型。
 - 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
 
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:
- 子类方法访问权限为 public,大于父类的 protected。
 - 子类的返回类型为 ArrayList
,是父类返回类型 List 的子类。  - 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
 - 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
```java
class SuperClass {
  protected List
func() throws Throwable { 
} }return new ArrayList<>();
 
class SubClass extends SuperClass {
    @Override
    public ArrayList
在调用一个方法时,先从本类中查找看是否有对应的方法,如果没有再到父类中查看,看是否从父类继承来。否则就要对参数进行转型,转成父类之后看是否有对应的方法。总的来说,方法调用的优先级为:- this.func(this)- super.func(this)- this.func(super)- super.func(super)```java/*A|B|C|D*/class A {public void show(A obj) {System.out.println("A.show(A)");}public void show(C obj) {System.out.println("A.show(C)");}}class B extends A {@Overridepublic void show(A obj) {System.out.println("B.show(A)");}}class C extends B {}class D extends C {}
public static void main(String[] args) {A a = new A();B b = new B();C c = new C();D d = new D();// 在 A 中存在 show(A obj),直接调用a.show(a); // A.show(A)// 在 A 中不存在 show(B obj),将 B 转型成其父类 Aa.show(b); // A.show(A)// 在 B 中存在从 A 继承来的 show(C obj),直接调用b.show(c); // A.show(C)// 在 B 中不存在 show(D obj),但是存在从 A 继承来的 show(C obj),将 D 转型成其父类 Cb.show(d); // A.show(C)// 引用的还是 B 对象,所以 ba 和 b 的调用结果一样A ba = new B();ba.show(c); // A.show(C)ba.show(d); // A.show(C)}
6.继承后的特点—构造方法
构造方法的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。(先有爸爸,才能有儿子)
继承后子类构方法器特点:子类所有构造方法的第一行都会默认先调用父类的无参构造方法
class Person {private String name;private int age;public Person() {System.out.println("父类无参");}// getter/setter省略}class Student extends Person {private double score;public Student() {//super(); // 调用父类无参,默认就存在,可以不写,必须在第一行System.out.println("子类无参");}public Student(double score) {//super(); // 调用父类无参,默认就存在,可以不写,必须在第一行this.score = score;System.out.println("子类有参");}}public class Demo07 {public static void main(String[] args) {Student s1 = new Student();System.out.println("----------");Student s2 = new Student(99.9);}}输出结果:父类无参子类无参----------父类无参子类有参
7.super
1.super可以用来引用直接父类的实际变量(和this相似,主要用来区分父类和子类的字段)
2.super可以用来调用直接父类构造函数(super()一定要放在第一行)
3.super可以用来调用直接父类方法.
public class Main{public static void mian(String[] args)Child child = new Child("Father","Child");child.test();}}class Father{protected String name;public Father(String name){this.name=name;}public void Say(){System.out.println("hello,child");}}class Child extends Father{private Stirng mame;public Child(String name1,String name2){super(name1);//调用直接父类构造函数this.name=name2;}public void test(){System.out.println(this.name);System.out.println(super.name);//引用直接父类的实例变量super.Say(); //调用父类的直接方法}}
- 访问父类的构造函数:
 
子类只能继承父类的默认构造函数,如果父类没有默认的构造函数,那子类不能从父类继承默认构造函数,
这时子类必须使用super()来实现对父类的非默认构造函数的调用.
- 访问父类的成员:如果子类重写了父类的某个方法,可以通过使用 super 关键字来引用父类的方法实现。
 
this和super的区别
- 相同点:
 
- super()和this()都必须在构造函数的第一行进行调用, 否则就是错误的
2. this() 和super()都指的是对象,所以,均不可以在static环境中使用。 
- 不同点:
 
- super() 主要是对父类构造函数的调用,this() 是对重载构造函数的调用
2. super() 主要是在继承了父类的子类的构造函数中使用,是在不同类中的使用; this() 主要
是在同一类的不同构造函数中的使用8.继承的特点
1.Java只支持单继承,不支持多继承。
2.一个类可以有多个子类。// 一个类只能有一个父类,不可以有多个父类。class A {}class B {}class C1 extends A {} // ok// class C2 extends A, B {} // error
3.可以多层继承。// A可以有多个子类class A {}class C1 extends A {}class C2 extends A {}
class A {}class C1 extends A {}class D extends C1 {}
顶层父类是Object类。所有的类默认继承Object,作为父类。
 
