一、OOP特征二:继承性(inheritance)
面向对象的特征之二:继承性 why?
一、继承性的好处:
① 减少了代码的冗余,提高了代码的复用性
② 便于功能的扩展
③ 为之后多态性的使用,提供了前提
二、继承性的格式:
class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
子类和父类的关系,不同于子集和集合的关系。
extends:延展、扩展
三、Java中关于继承性的规定:
1.一个类可以被多个子类继承。
2.Java中类的单继承性:一个类只能有一个父类
3.子父类是相对的概念。
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、其他类对于Object类的继承
1. 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
2. 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3. 意味着,所有的java类具有java.lang.Object类声明的功能。
演示示例:
public class Creature { public void breath(){ System.out.println("呼吸"); } }
public class Person extends Creature{ String name; private int age; public Person(){ } public Person(String name,int age){ this.name = name; this.age = age; } public void eat(){ System.out.println("吃饭"); sleep(); } private void sleep(){ System.out.println("睡觉"); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class Student extends Person{ // String name; // int age; String major; public Student(){ } public Student(String name,int age,String major){ this.name = name; // this.age = age; setAge(age); this.major = major; } // public void eat(){ // System.out.println("吃饭"); // } // // public void sleep(){ // System.out.println("睡觉"); // } public void study(){ System.out.println("学习"); } public void show(){ System.out.println("name:" + name + ",age:" + getAge()); } }
public class ExtendsTest { public static void main(String[] args) { Person p1 = new Person(); // p1.age = 1; p1.eat(); System.out.println("*****************"); Student s1 = new Student(); s1.eat(); // s1.sleep(); s1.name = "Tom"; s1.setAge(10); System.out.println(s1.getAge()); s1.breath(); Creature c = new Creature(); System.out.println(c.toString()); } }
练习题:
1、
/* * 定义一个ManKind类,包括 成员变量int sex和int salary; 方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0); 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。 */ public class ManKind { private int sex;//性别 private int salary;//薪资 public ManKind() { } public ManKind(int sex, int salary) { this.sex = sex; this.salary = salary; } public void manOrWoman(){ if(sex == 1){ System.out.println("man"); }else if(sex == 0){ System.out.println("woman"); } } public void employeed(){ // if(salary == 0){ // System.out.println("no job"); // }else{ // System.out.println("job"); // } //或 String jobInfo = (salary == 0)? "no job" : "job"; System.out.println(jobInfo); } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } }
/* * 定义类Kids继承ManKind,并包括 成员变量int yearsOld; 方法printAge()打印yearsOld的值。 */ public class Kids extends ManKind{ private int yearsOld; public Kids() { } public Kids(int yearsOld) { this.yearsOld = yearsOld; } public void printAge(){ System.out.println("I am " + yearsOld + " years old."); } public int getYearsOld() { return yearsOld; } public void setYearsOld(int yearsOld) { this.yearsOld = yearsOld; } }
/* * 定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。 */ public class KidsTest { public static void main(String[] args) { Kids someKid = new Kids(12); someKid.printAge(); someKid.setSalary(0); someKid.setSex(1); someKid.employeed(); someKid.manOrWoman(); } }
2、
public class Circle { private double radius;//半径 public Circle(){ radius = 1.0; } // public Circle(double radius){ this.radius = radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } //返回圆的面积 public double findArea(){ return Math.PI * radius * radius; } }
public class Cylinder extends Circle{ private double length;//高 public Cylinder(){ length = 1.0; } public double getLength() { return length; } public void setLength(double length) { this.length = length; } //返回圆柱的体积 public double findVolume(){ // return Math.PI * getRadius() * getRadius() * getLength(); return super.findArea() * getLength(); } @Override public double findArea() {//返回圆柱的表面积 return Math.PI * getRadius() * getRadius() * 2 + 2 * Math.PI * getRadius() * getLength(); } }
public class CylinderTest { public static void main(String[] args) { Cylinder cy = new Cylinder(); cy.setRadius(2.1); cy.setLength(3.4); double volume = cy.findVolume(); System.out.println("圆柱的体积为:" + volume); //没有重写findArea()时: // double area = cy.findArea(); // System.out.println("底面圆的面积:" + area); //重写findArea()以后: double area = cy.findArea(); System.out.println("圆柱的表面积:" + area); System.out.println("******************"); Cylinder cy1 = new Cylinder(); double volume1 = cy1.findVolume(); System.out.println("圆柱的体积为:" + volume1); } }
二、方法的重写(override or overwrite)
方法的重写(override / overwrite)
1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
3. 重写的规定:
方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
//方法体
}
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
>特殊情况:子类不能重写父类中声明为private权限的方法
③ 返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
>父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲)
*************************************************************************************************
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。
面试题:区分方法的重载与重写
演示示例:
public class Person { String name; int age; public Person(){ } public Person(String name,int age){ this.name = name; this.age = age; } void eat(){ System.out.println("吃饭"); } public void walk(int distance){ System.out.println("走路,走的距离是:" + distance + "公里"); show(); eat(); } private void show(){ System.out.println("我是一个人"); } public Object info(){ return null; } public double info1(){ return 1.0; } }
public class Student extends Person{ String major; public Student(){ } public Student(String major){ this.major = major; } public void study(){ System.out.println("学习。专业是:" + major); } //对父类中的eat()进行了重写 public void eat(){ System.out.println("学生应该多吃有营养的食物"); } public void show(){ System.out.println("我是一个学生"); } public String info(){ return null; } // public int info1(){ // return 1; // } // public void walk(int distance){ // System.out.println("重写的方法"); // } public void walk(int distance) { System.out.println("重写的方法"); } }
public class PersonTest { public static void main(String[] args) { Student s = new Student("计算机科学与技术"); s.eat(); s.walk(10); System.out.println("**************"); s.study(); Person p1 = new Person(); p1.eat(); } }
练习题:
public void employeed() { System.out.println("Kids should study and no job."); }
三、四种访问权限修饰符的使用(private、缺省(default)、protected、public)
演示示例:
/* * 体会4种不同的权限修饰 * * */ public class Order { private int orderPrivate; int orderDefault; protected int orderProtected; public int orderPublic; private void methodPrivate(){ orderPrivate = 1; orderDefault = 2; orderProtected = 3; orderPublic = 4; } void methodDefault(){ orderPrivate = 1; orderDefault = 2; orderProtected = 3; orderPublic = 4; } protected void methodProtected(){ orderPrivate = 1; orderDefault = 2; orderProtected = 3; orderPublic = 4; } public void methodPublic(){ orderPrivate = 1; orderDefault = 2; orderProtected = 3; orderPublic = 4; } }
public class OrderTest { public static void main(String[] args) { Order order = new Order(); order.orderDefault = 1; order.orderProtected = 2; order.orderPublic = 3; order.methodDefault(); order.methodProtected(); order.methodPublic(); //同一个包中的其他类,不可以调用Order类中私有的属性、方法 // order.orderPrivate = 4; // order.methodPrivate(); } }
package com.atguigu.java3; import com.atguigu.java2.Order; public class OrderTest { public static void main(String[] args) { Order order = new Order(); order.orderPublic = 1; order.methodPublic(); //不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法 // order.orderPrivate = 2; // order.orderDefault = 3; // order.orderProtected = 4; // // order.methodPrivate(); // order.methodDefault(); // order.methodProtected(); } public void show(Order order){ order.orderPublic = 1; order.methodPublic(); //不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法 // order.orderPrivate = 2; // order.orderDefault = 3; // order.orderProtected = 4; // // order.methodPrivate(); // order.methodDefault(); // order.methodProtected(); // } }
package com.atguigu.java3; import com.atguigu.java2.Order; public class SubOrder extends Order { public void method(){ orderProtected = 1; orderPublic = 2; methodProtected(); methodPublic(); //在不同包的子类中,不能调用Order类中声明为private和缺省权限的属性、方法 // orderDefault = 3; // orderPrivate = 4; // // methodDefault(); // methodPrivate(); } }
四、关键字:super 的使用
super关键字的使用:
1.super理解为:父类的
2.super可以用来调用:属性、方法、构造器
3.super的使用:调用属性和方法
3.1 我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用
父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的
使用"super.属性"的方式,表明调用的是父类中声明的属性。
3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的
使用"super.方法"的方式,表明调用的是父类中被重写的方法。
4.super调用构造器
4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!
4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
4.4 在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列表)",则默认调用的是父类中空参的构造器:super()
4.5 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器
演示示例:
public class Person { String name; int age; int id = 1001;//身份证号 public Person(){ System.out.println("我无处不在!"); } public Person(String name){ this.name = name; } public Person(String name,int age){ this(name); this.age = age; } public void eat(){ System.out.println("人:吃饭"); } public void walk(){ System.out.println("人:走路"); } }
public class Student extends Person{ String major; int id = 1002;//学号 public Student(){ super(); } public Student(String major){ super(); this.major = major; } public Student(String name,int age,String major){ // this.name = name; // this.age = age; super(name,age); this.major = major; } @Override public void eat() { System.out.println("学生:多吃有营养的食物"); } public void study(){ System.out.println("学生:学习知识"); this.eat(); super.eat(); walk(); } public void show(){ System.out.println("name = " + name + ", age = " + age); System.out.println("id = " + this.id); System.out.println("id = " + super.id); } }
public class SuperTest { public static void main(String[] args) { Student s = new Student(); s.show(); System.out.println(); s.study(); Student s1 = new Student("Tom", 21, "IT"); s1.show(); System.out.println("************"); Student s2 = new Student(); } }
练习题:(之前的代码已实现)
五、子类对象的实例化过程(了解机理)
子类对象实例化的全过程:
1. 从结果上来看:(继承性)
子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
2. 从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,...
直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有
父类中的结构,子类对象才可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
六、OOP特征三:多态性
面向对象特征之三:多态性
1.理解多态性:可以理解为一个事物的多种形态。
2.何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3. 多态的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边。
4.多态性的使用前提: ① 类的继承关系 ② 方法的重写
5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
演示示例:
public class Person { String name; int age; int id = 1001; public void eat(){ System.out.println("人:吃饭"); } public void walk(){ System.out.println("人:走路"); } }
public class Man extends Person{ boolean isSmoking; int id = 1002; public void earnMoney(){ System.out.println("男人负责挣钱养家"); } public void eat(){ System.out.println("男人多吃肉,长肌肉"); } public void walk(){ System.out.println("男人霸气的走路"); } }
public class Woman extends Person{ boolean isBeauty; public void goShopping(){ System.out.println("女人喜欢购物"); } public void eat(){ System.out.println("女人少吃,为了减肥"); } public void walk(){ System.out.println("女人窈窕的走路"); } }
public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.eat(); Man man = new Man(); man.eat(); man.age = 25; man.earnMoney(); //************************************************* System.out.println("*******************"); //对象的多态性:父类的引用指向子类的对象 Person p2 = new Man(); // Person p3 = new Woman(); //多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用 p2.eat(); p2.walk(); // p2.earnMoney(); System.out.println(p2.id);//1001 } }
多态的举例:
import java.sql.Connection; //多态性的使用举例一: public class AnimalTest { public static void main(String[] args) { AnimalTest test = new AnimalTest(); test.func(new Dog()); test.func(new Cat()); } public void func(Animal animal){//Animal animal = new Dog(); animal.eat(); animal.shout(); if(animal instanceof Dog){ Dog d = (Dog)animal; d.watchDoor(); } } // public void func(Dog dog){ // dog.eat(); // dog.shout(); // } // public void func(Cat cat){ // cat.eat(); // cat.shout(); // } } class Animal{ public void eat(){ System.out.println("动物:进食"); } public void shout(){ System.out.println("动物:叫"); } } class Dog extends Animal{ public void eat(){ System.out.println("狗吃骨头"); } public void shout(){ System.out.println("汪!汪!汪!"); } public void watchDoor(){ System.out.println("看门"); } } class Cat extends Animal{ public void eat(){ System.out.println("猫吃鱼"); } public void shout(){ System.out.println("喵!喵!喵!"); } } //举例二: class Order{ public void method(Object obj){ } } //举例三: class Driver{ public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection(); //规范的步骤去操作数据 // conn.method1(); // conn.method2(); // conn.method3(); } }
面试题:多态是编译时行为还是运行时行为?
import java.util.Random; //面试题:多态是编译时行为还是运行时行为? //证明如下: class Animal { protected void eat() { System.out.println("animal eat food"); } } class Cat extends Animal { protected void eat() { System.out.println("cat eat fish"); } } class Dog extends Animal { public void eat() { System.out.println("Dog eat bone"); } } class Sheep extends Animal { public void eat() { System.out.println("Sheep eat grass"); } } public class InterviewTest { public static Animal getInstance(int key) { switch (key) { case 0: return new Cat (); case 1: return new Dog (); default: return new Sheep (); } } public static void main(String[] args) { int key = new Random().nextInt(3); System.out.println(key); Animal animal = getInstance(key); animal.eat(); } }
每日一考复习题
1、什么是多态性?什么是虚拟方法调用?
对象的多态性:父类的引用指向子类的对象。
Person p = new Man();
p.eat();
调用方法时,编译时看左边,运行时看右边。
2、一个类可以有几个直接父类?(只有一个)一个父类可有多少个子类?(多个)子类能获取直接父类的父类中的结构吗?(可以)子类能否获取父类中private权限的属性或方法?(可以的)
A is a B
3、方法的重写(override/overwrite)的具体规则有哪些?
方法名、形参列表相同
权限修饰符
返回值
抛出的异常
4、super调用构造器,有哪些具体的注意点
this(形参列表):本类重载的其它的构造器
super(形参列表):调用父类中指定的构造器
n 、n – 1、 1
5、在下面的代码结构中:使用关键字:this,super;方法的重写;继承;
七、Object类的使用
java.lang.Object类
1.Object类是所有Java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
3.Object类中的功能(属性、方法)就具有通用性。
属性:无
方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
wait() 、 notify()、notifyAll()
4. Object类只声明了一个空参的构造器
面试题:
final、finally、finalize的区别?
例:
public class ObjectTest { public static void main(String[] args) { Order order = new Order(); System.out.println(order.getClass().getSuperclass()); } } class Order{ }
==操作符与equals方法
一、回顾 == 的使用:
== :运算符
1. 可以使用在基本数据类型变量和引用数据类型变量中
2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
补充: == 符号使用时,必须保证符号左右两边的变量类型一致。
二、equals()方法的使用:
1. 是一个方法,而非运算符
2. 只能适用于引用数据类型
3. Object类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
4. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是
两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
5. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
就需要对Object类中的equals()进行重写.
重写的原则:比较两个对象的实体内容是否相同.
例:
public class EqualsTest { public static void main(String[] args) { //基本数据类型 int i = 10; int j = 10; double d = 10.0; System.out.println(i == j);//true System.out.println(i == d);//true boolean b = true; // System.out.println(i == b); char c = 10; System.out.println(i == c);//true char c1 = 'A'; char c2 = 65; System.out.println(c1 == c2);//true //引用类型: Customer cust1 = new Customer("Tom",21); Customer cust2 = new Customer("Tom",21); System.out.println(cust1 == cust2);//false String str1 = new String("atguigu"); String str2 = new String("atguigu"); System.out.println(str1 == str2);//false System.out.println("****************************"); System.out.println(cust1.equals(cust2));//false--->true System.out.println(str1.equals(str2));//true Date date1 = new Date(32432525324L); Date date2 = new Date(32432525324L); System.out.println(date1.equals(date2));//true } }
面试题: == 和 equals() 区别: