P284-继承P289Super关键字P302覆盖P306-P311多态
P284无参数构造器与setXxx()方法集合练习1
package Encap; public class Person { public static void main(String[] args) { Person1 p1 = new Person1(); p1.setName("javakkkk"); p1.setAge(200); p1.setSalary(9999); System.out.println(p1.info()); Person1 p2 = new Person1("simi",400,999);//利用构造器指定属性 System.out.println(p2.info()); } } class Person1{ public String name; private int age; private double salary; public Person1(String name, int age, double salary) {//有三个属性的构造器 this.name = name;//如果是单独构造器就不具备setX()的作用 this.age = age; this.salary = salary; //所以我们可以将set方法写入构造器 setName(name); setAge(age); setSalary(salary); } public Person1() { } public int getAge(){ return age; } public void setAge(int age){ if(age <1 || age > 120){ System.out.println("年龄需在1-120"); this.age=20; }else{ this.age=age; } } public void setName(String name) { if(name.length() >= 6 || name.length() <=2 ){ System.out.println("名字长度不对,需要2-6"); this.name="null"; }else { this.name = name; } } public double getSalary(int a) {//可以增加对象的权限判断 return a != 666 ? 0:salary; } public void setSalary(double salary) { this.salary = salary; } public String info(){ return("name= "+name+" age= "+age+" salary= "+salary); } }
P285练习
package Encap; public class Acount { private String name; private double balance; private String pwd; public Acount() { } public Acount(String name, double balance, String pwd) { this.setName(name); this.setBalance(balance); this.setPwd(pwd); } public void setName(String name) { if(name.length() > 4 || name.length() < 2){ System.out.println("name在2-4位"); this.name="无名"; }else { this.name = name; } } public String getName() { return name; } public double getBalance() { return balance; } public void setBalance(double balance) { if(balance > 20.0) { this.balance = balance; }else{ System.out.println("balance > 20,否则默认为0"); this.balance=0.0; } } public String getPwd() { return pwd; } public void setPwd(String pwd) { if( pwd.length() == 6) { this.pwd = pwd; }else{ System.out.println("密码必须为6位,否则默认000000"); this.pwd="000000"; } } public void info(){ System.out.println("name= "+name +" balance= "+balance +" pwd= "+pwd); } }
package Encap; public class AcountTest { public static void main(String[] args) { Acount acount = new Acount(); acount.setPwd("1234567"); acount.setBalance(9); acount.setName("lllll"); acount.info(); } }
P286继承
1.由于两个类许多属性和方法相同,所以需要继承
-----
2.继承的规则
-----
3.代码
package com.extend; //源类 public class Student { public String name; public int age; private double score; public void setScore(double score) { this.score = score; } public void showinfo(){ System.out.println("学生 "+name +" age "+age+" score "+score); } }
package com.extend; //让pupil继承student public class Pupil extends Student { public void testing(){ System.out.println("小学生 "+name+" testing"); } } package com.extend; //让graduate继承student public class Graduate extends Student { public void testing(){ System.out.println("大学生 "+name+" testing"); } }
package com.extend; public class TestEx {//测试调用 public static void main(String[] args) { Pupil p = new Pupil(); p.name="Ada"; p.age=10; p.testing(); p.setScore(100); p.showinfo(); System.out.println("========="); Graduate g = new Graduate(); g.name="Beta"; g.age=99; g.testing(); g.setScore(150); g.showinfo(); } }
4.继承细节
-
package com.extend; //源类(个人比较喜欢叫源类) public class Student { public int n1=100; protected int n2=200; int n3=300; private int n4=400; public Student() {//无参构造器 System.out.println("源类Student()构造器被调用"); } public int getNe(){//源类提供一个公公共方法去访问n4 return n4; } public void calltest400(){ test400(); } public void test100() { System.out.println("test100"); } protected void test200(){ System.out.println("test200"); } void test300(){ System.out.println("test300"); } private void test400(){ System.out.println("test400"); } }
package com.extend; //让graduate继承student public class Graduate extends Student { public Graduate() { super();//默认调用父类的无参构造器,写不写都可以 system.out.println("子类Graduate()构造器被调用") } public void sayOK(){//子类的方法 // 非私有的属性和方法在子类中可以直接访问,私有要通过公共方法去访问 System.out.println(n1+n2+n3);//不能访问n4,不能访问test400(); test100(); test200(); test300(); //源类提供的公共方法去访问 System.out.println("n4="+getNe()); calltest400(); } }
package com.extend; public class TestEx {//测试调用 public static void main(String[] args) { Graduate g = new Graduate(); g.sayOK(); } }
输出
源类Student()构造器被调用
子类Graduate()构造器被调用
600 test100 test200 test300 n4=400 test4
-具体可见上层述代码,源类构造器先调用,再调用子类的构造器
-
第一句话理解(注意此时源类只有一个无参构造器)
package com.extend; //让graduate继承student public class Graduate extends Student { public Graduate() { System.out.println("子类的无参构造器被调用"); } public Graduate(int n3){ System.out.println("子类构造器int n3被调用()");//源类不变,增加一个构造器 }
package com.extend; public class TestEx {//测试调用 public static void main(String[] args) { Graduate g = new Graduate(); System.out.println("第二个对象"); Graduate g2 = new Graduate(3000); g.sayOK(); g2.sayOK(); } }
输出结果为
父类Student()无参构造器调用 子类的无参构造器被调用 第二个对象 父类Student()无参构造器调用 子类构造器int n3被调用() 600 test100 test200 test300 n4=400 test400 600 test100 test200 test300 n4=400 test400
第二句话理解(此时源类有Student(int 1,int2)构造器,将默认构造器覆盖了)
public class Student { public int n1=100; protected int n2=200; int n3=300; private int n4=400; //public Student() {//无参构造器 // System.out.println("父类Student()无参构造器调用"); //} public Student(int n1,int n2){ System.out.println("源类Student(int n1,int n2)构造器被调用了"); } package com.extend; //让graduate继承student public class Graduate extends Student { public Graduate() { super(100,200); System.out.println("子类的Graduate构造器被调用"); } public Graduate(int n3){ super(100,200); System.out.println("子类构造器Graduate(int n3)被调用()"); }
输出结果为
源类Student(int n1,int n2)构造器被调用了 子类的Graduate构造器被调用 第二个对象 源类Student(int n1,int n2)构造器被调用了 子类构造器Graduate(int n1,int n2)被调用()
如果调用源类可以什么都不写,或者super();如果参数,比如name,super("jack");
--
可以在ctrl+H察看类的关系
5.继承本质的分析(theoray原理)
package com.extend; public class Theoray { public static void main(String[] args) { D d = new D(); System.out.println(d.name+d.age+d.hobby); } } class G{ String name="姥姥"; String hobby="money"; } class M extends G{ String name="mon"; int age =45; } class D extends M{ String name="dau"; }
-
顺序:
1.new D,继承关系Object-G-M-D,所以从D-M-G-O
2.对象在栈——在堆----方法区常量值存储String 类型数据
3.当访问D.属性的时候,先看子类是否有这个属性,如果有并且可以访问,则访问。
(上文说过如果私有变量可以通过父类方法进行访问
class M extends G{ String name="mon"; private int age =45; public int getAge() { return age; } //在System.out.println(d.name+d.getAge()+d.hobby);
注意一个点,上文比如我调用d.age,比如G和M都有age,M是私有,G是公有的,实际上不会调用,因为在M已经堵住了,有顺序的,所以不会继续调用G的age属性)
如果子类没有这个属性,就看源类继续上一级
依次输出 dau45money
6.面向对象的编程继承练习
-
分析:B(){this("abc")执行下面构造器,然后返回A的无参构造器
练习2
public class Computer { private String cpu; private int memory; private int disk; public Computer(String cpu, int memory, int disk) { this.cpu = cpu; this.memory = memory; this.disk = disk; System.out.println("调用C(1,2,3)构造器"); } public String getDetial(){ return "cpu="+cpu+" memory="+memory+" disk="+disk; } }
package com.extend; public class PC extends Computer{ private String band; public PC(String cpu, int memory, int disk, String band) { //IDEA根据继承的思想,父类继承的初始化 //子类构造器完成子类属性的初始化 super(cpu, memory, disk); this.band = band; } public void printInfo(){ System.out.println(getDetial()+"brand= "+band); //通过父类的方法得到信息 } }
package com.extend; public class NotePad extends Computer { private String color; public NotePad(String cpu, int memory, int disk, String color) { super(cpu, memory, disk); this.color = color; } public void Printinfo(){ System.out.println(getDetial()+"color="+color); } }
package com.extend; public class Test { public static void main(String[] args) { PC pc = new PC("intel",4,5,"IBM"); pc.printInfo(); System.out.println("====第二个对象==="); NotePad nP = new NotePad("tian",7,8,"blue"); nP.Printinfo();
P289Super关键字
--
public class A{ public int a; private String b; double c; public A() { } public A(int a) { this.a = a; } public A(int a, String b, double c) { this.a = a; this.b = b; this.c = c; } public void Testa(){ } private void Testb(){ } } public class B extends A{ public int d; public void Test(){//调用父类的属性非private System.out.println(super.a+super.c); } public void OK(){//调用父类的方法,非private super.Testa(); } public B(){ // super ();继承无参构造器 super (10);//调用的是父类的构造器,public A(int a) } }
-
package Super; public class A { public int a; private String b; double c; public A(int a, String b, double c) { this.a = a; this.b = b; this.c = c; } public void Testa(){ } } class B extends A{ public int d; public void OK(){//调用父类的方法,非private //当想要调用父类中的Testa()方法的时候,有三种方式 //Testa(); //找此方法的时候,顺序是先找本类, // 本类有再并且可以调用,则调用, // 无则找父类,一直找,直到Object类 // 如果在过程中找到但不可访问则报错,或者方法不存在 // this.Testa();//等价上述的Testa() super.Testa();//跳过子类(如果子类有同样名字的方法或者没有都会跳过) //是直接找父类的Testa(),后面步骤和上一样直到Object类 //演示调用属性的规则,同上 System.out.println(a); System.out.println(this.a); System.out.println(super.a); }
-
P302方法重写/覆盖(override)
``
不一定是父子关系,只是相对而言,比如A-B-C,A-C之间也有可能
-
重写可以通过编译,比如B继承A,父类返回类型A,子类返回类型可以为A也可以为B
注意,子类的范围不能缩小
-
补充一下,重载的形参可以是普通参数+可变参数,可变参数放在最后且一个形参只能一个可变参数P235
练习code
package com; public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String say(){//注意为了简洁,没有写set()和get()方法 return "name= "+name+"age= "+age; } }
public class Student extends Person { private int id; private int score; public Student(String name, int age, int id, int score) { super(name, age); this.id = id; this.score = score; } public String say(){//此时属于方法重写了 return super.say()+" id="+id+" score="+score; } public void setScore(int score) { this.score = score; } }
package com; public class OverdideExercise { public static void main(String[] args) { Person p1 = new Person("Pp",9); System.out.println(p1.say()); System.out.println("第二个对象"); Student s = new Student("Ss",20,6666,99); System.out.println(s.say()); } }
P306多态polymorphic
--
---
2)对象的多态
上图 父类发引用 Anima; animal ,指向,子类的对象 new Dog();
package com.Polymoraphic.Exercise; public class Animal {//父类 public void cry(){ System.out.println("A在叫"); } }
package com.Polymoraphic.Exercise; public class Dog extends Animal {//子类1 public void cry(){ System.out.println("dog瞎叫"); } }
package com.Polymoraphic.Exercise; public class Cat extends Animal//子类2 public void cry(){ System.out.println("cat在叫"); } }
package com.Polymoraphic.Exercise; public class Test { public static void main(String[] args) { //体验对象的多态特点 Animal animal= new Dog();//注意 Dog是Animal的子类才可以 animal.cry();//因为运行时, 执行到该行时,animal // 运行类型是Dog,所以cry 就是Dog 的cry animal = new Cat();//编译还是animal,but 运行类型是Cat //运行的时候看的是堆里的指向 animal.cry(); } }
public void feed(Animal animal,Food food){
\\ animal的编译类型是Animal ,可以指向接收Animal子类的对象
system.out.println(animal.getName +feed.getName)
}
P310多态的注意事项和细节
向上引用 例如上文 A nimal animal = new Dog();code为举例
package com.Polymoraphic.Exercise; public class Animal { public void eat(){ System.out.println("A在eat"); } public void run(){ System.out.println("A在run~"); } public void sleep(){ System.out.println("A在sleep~"); } }
package com.Polymoraphic.Exercise; public class Cat extends Animal{ public void eat (){ System.out.println("cat在eat"); } public void catchM () { System.out.println("cat抓老鼠"); } }
package com.Polymoraphic.Exercise; public class Test { public static void main(String[] args) { //向上转型,父类的引用指向子类的对象 Animal animal=new Cat(); //Object object = new Cat();也可以 //可以访问父类中的所有成员(需遵守访问权限,比如private) /*但是不能访问子类的特有成员ainimal.catch 因为在编译阶段,能调用哪些成员,由编译类型来决定 */ //最终运行效果看子类的具体实现,调用方法的时候从子类开始查找,规则与方法调用规则一致 animal.eat();//cat在eat animal.run();//A在run~ animal.sleep();//A在sleep~ } }
向下转型
package com.Polymoraphic.Exercise; public class Test { public static void main(String[] args) { //向上转型,父类的引用指向子类的对象 Animal animal=new Cat(); //向下转型,语法 子类类型 引用名=(子类类型)父类引用 //此时编译类型Cat,运行类型也是Cat //(2)要求父类的引用必须指向的是当前目标类型的对象 //意思是下行的animal实际上指向Cat对象,cat1也指向Cat对象 //原本的时候animal>Animal,cat1>Cat对象 //把指向猫的animal转向cat Cat cat1 = (Cat) animal; cat1.catchM();//调用这个方法,得到猫类的特有方法 Animal animal1 = new Dog(); Dog dog = (Dog) animal1;//个人认为多态的向下需要向上 // 使得父类的引用指向当前目标类型的对象 dog.cry(); }