代码块
代码块的概念:
用{}括起来的代码都是代码块。{}里面是他的作用域,在{}里面定义的方法和变量会在{}执行完成后被垃圾回收器回收(这一句是我猜的)。
代码块的分类:
静态代码块:在类的成员位置被static修饰的代码块。 对
类进行初始化。
静态代码块只能执行一次!!!!
构造代码块:在一个类的成员位置被{}括起来的部分。 可以将多个构造方法放到构造代码块中,对
对象进行初始化。
构造方法:这个概念应该在面向对象第一阶段就了解到了。
局部代码块: 在main()里面,给变量限定它的生命周期。 给变量限定他的生命周期。
代码块的优先级:
静态代码块>局部代码块>构造代码块>构造方法
实例:
class Code{ //静态代码块:优先级第二高,第二执行 static{ int x = 1000 ; System.out.println(x); } //成员位置 { int x = 100 ; System.out.println(x); } //构造方法 public Code() { System.out.println("code"); } //构造代码块 { int y = 200 ; System.out.println(y); } //有参构造 public Code(int a) { System.out.println("code"); } //静态代码块 static { int y = 2000 ; System.out.println(y); } } public class CodeDemo { public static void main(String[] args) { //局部代码块:优先级最高最先执行 { int x = 10 ; System.out.println(x); } //局部代码块 { int y = 20 ; System.out.println(y); } //创建Code类的对象 Code code = new Code() ; System.out.println("--------------------"); Code code2 = new Code() ; System.out.println("--------------------"); Code code3 = new Code(100) ; } }
执行顺序:先加载main方法,在main方法中只有连个局部代码块以及创建3个对象,所以按顺序执行。执行完局部代码块后,我们开始创建Code的对象,创建对象之前我们需要先加载类,加载类时因为有两个静态代码块,所以我们优先顺序执行两个静态代码块。静态代码块只执行一次,执行完毕后静态代码块不复存在。然后我们执行的是Code类中的局部代码块,执行完毕后执行构造代码块,最后是有参构造。
所以我们的控制台输出的结果是:
所以我们的控制台输出的结果是:
1000 2000 100 200 code -------------------- 100 200 code -------------------- 100 200 code
继承
什么是继承?
为什么要引入继承?
在我们创建多个具有存在相同属性或者行为的类时,会因为内容的高度重复造成代码的冗长,所以我们把具有相同属性或方法的部分拿出来,送给一个独立的类,这个独立的类叫做父类,而被提取者称为子类,子类可以继承父类的所有,除了构造方法,构造方法我们可以用调用的方法访问。
继承就是将多个类的共有内容抽取出来作为一个独立的类,让这个独立的类和被提取类之间产生一种关系,这种关系就叫做继承关系。
继承的语法
class 父类名{
}
class 子类名 extends 父类名{
}
语法规定,对于继承不能存在多继承,只能单继承。但是可以支持多层继承。
继承的好处、特点
继承提供了代码的复用性,解决了代码的臃肿问题。
子类继承父类是继承了父类的所有,包括成员变量、成员方法甚至私有的变量和方法。但是子类不能直接使用父类的私有资源,只能通过父类公共访问间接访问私有资源。
子类不能直接继承父类的构造方法,但是可以通过super关键字访问。
父类完全属于子类的时候在使用继承。
子类继承父类都要默认访问父类的无参构造方法。原因:假如 数据没有初始化完毕,所以应该先让父类进行初始化,然后让子类进行初始化——分层初始化。
例子
class Father{//这是一个父类 int money; private int age; private String name; public void Fa() { System.out.println("i am father"); } private void Fa1() { } public Father() { super(); } public Father(int money, int age, String name) { super(); this.money = money; this.age = age; this.name = name; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Son extends Father{//这是一个子类 private String hoby ; int num; public void Aloha(){ System.out.println("i am son"); } public Son() { super(); } public Son(int money, int age, String name,String hoby) { super(money, age, name); } public String getHoby() { return hoby; } public void setHoby(String hoby) { this.hoby = hoby; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } } public class time8_50 { public static void main(String[] args) { Son s = new Son(); //通过对象s无法访问父类的私有成员变量和私有成员方法。 s.Fa(); s.setNum(10); s.setHoby("pingpang"); System.out.println(s.getNum() + "-"+s.getHoby()); //创建父类的对象 Father f = new Father(); //创建完父类的对象后,子类对象可以调用父类的方法和非私有变量 s.setAge(80); s.setMoney(210); s.setName("zhangsan"); System.out.println(s.getName() + " " + s.getAge() + " " + s.getMoney() + " son:" + s.getNum() + " " + s.getHoby()); } }
super关键字
this关键字时用来指向类中的成员位置,尤其是在局部变量和成员变量同的名的情况下。
super的作用意义和this差不多,super用来指向父类中的成员位置,也是可以区分父类和子类、子类方法中同名的关键字。
例如:
class Father1{ public int num = 100; } class Son1 extends Father1{ public int num = 10 ; public void show() { int num = 5; System.out.println(num);//找寻顺序:子类方法中--->子类成员位置--->父类成员位置 到不了父类的方法中 System.out.println(this.num);//this可以在成员变量和局部变量同名的情况下指定成员变量 System.out.println(super.num);//super可以在成员变量和局部变量和父类中变量名相同的情况下直接指向父类中的变量。 } } public class time11_02 { public static void main(String[] args) { Son1 s =new Son1(); s.show(); } }
控制台输出的结果是:
5
10
100
super(&this)关键字的用法
都可访问: 成员变量 this.成员变量;//访问当前类的成员变量 super.成员变量;//访问父类的成员变量
成员方法 this.方法名;//访问当前类的成员方法 super.方法名;//访问父类的成员方法
构造方法 this();//访问无参构造 this(" ") ; //访问当前类的有参构造
super(); // 访问父类的无参构造 super(" ");//访问父类的有参构造
多态
同一时刻,体现出不同而状态。
多态的前提:
1.必须有继承关系
2.必须有方法重写
3.必须有父类的引用指向子类的对象(向上转型)
访问特点:
父类名 fu = new 子类名();
class Fu{
int num = 10 ;
public void Num() {
System.out.println("父类的测试类");
}
}
class Zi extends Fu{
int num = 20 ;
public void Num() {//方法重写
System.out.println("子类的测试类");
}
}
public class Test1 {
public static void main(String[] args) {
Fu f = new Zi();//父类的引用指向子类的对象
System.out.println(f.num);
f.Num();
}
}
以上代码运行的结果是,输出num = 10 ; 输出Num的为“子类测试类”。我们可以得出结论:对于成员变量的引用我们关注父类;对于成员方法(非静态),因为有方法重写,所以我们得关注子类。对于静态方法,因为静态的方法随着类的加载类加载,故算不上方法重写,所以创建对象后还是要看父类。
多态的好处:提高代码的复用性(继承提供);提高代码的扩展性(多态提供)。
例如:
class Animal{ public void eat() { System.out.println("吃"); } public void sleep() { System.out.println("睡"); } } class Dog extends Animal{ public void eat() { System.out.println("狗吃屎"); } public void sleep() { System.out.println("狗睡觉"); } } class Cat extends Animal{ public void eat() { System.out.println("猫吃猫粮"); } public void sleep() { System.out.println("猫睡觉"); } } class Pet extends Animal{ private Pet() {//不让创建Pet的对象 } public static void PetTest(Animal a) { a.eat(); a.sleep(); } } public class Test2 { public static void main(String[] args) { Animal c = new Cat(); Animal d = new Dog(); Pet.PetTest(c); Pet.PetTest(d); } }
这样可以在重复一个动作时大大减少程序的冗余。
向下转型(强制类型转换)的内存图解:
class Animal2{ public void eat() { } } //猫类 class Cat2 extends Animal2 { public void eat() {} public void playGame() {} } //狗类: class Dog2 extends Animal2{ public void eat() {} public void lookDoor() {} } //测试类 public class DuoTaiDemo5 { public static void main(String[] args) { //内存中是猫 Animal a = new Cat() ; //向下转型 //还原成猫 Cat c = (Cat)a; //内存中变成了Dog a = new Dog() ; //还原成狗 Dog d = (Dog)a ; Cat cc = (Cat)a ;//这句就会转换异常 } }
例子2:
class Person{ public void eat() { System.out.println("吃饭..."); } } //南方人 class SourthPeople extends Person{ public void eat() { System.out.println("南方人吃米饭..."); } //特有功能 public void business() { System.out.println("南方人爱经商..."); } } //北方人 class NorthPeople extends Person{ public void eat(){ System.out.println("北方人爱吃面..."); } //特有功能 public void yanJiu() { System.out.println("北方人爱钻研..."); } } //测试类 public class DuoTaiTest2 { public static void main(String[] args) { //多态:向上转型 Person p = new SourthPeople() ;//向上转型无法访问子类特有的东西 p.eat(); //向下转型 SourthPeople sp = (SourthPeople)p;//sp指向SourthPeople sp.business(); System.out.println("-------"); //实际开中:是什么类,给什么了类的对象 SourthPeople sp2 = new SourthPeople() ; sp2.eat(); sp2.business(); } }SourthPeople sp = (SourthPeople)p;//sp指向SourthPeople 需要特别特别理解!!!