5 - 1 面向对象特征之二:继承性
1.继承性的优点
1)减少了代码的冗余,提高了代码的副用性
2)便于功能的扩展
3)为之后多态性的使用,提供了前提
2.继承性的格式:
class A extends B
{
}
A: 子类、派生类、subclass
B: 父类、超类、基类、superclass
2.1体现:一旦子类A继承父类B后,子类A中就获取了父类B中声明的结构:属性、方法
特别的:父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已
2.2子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展
2.3子类和父类的关系,不同于子集和集合的关系
extends : 延展、拓展
3.Java中关于继承性的规定
1)一个类可以被多个子类继承
2)Java中类的单继承性:一个类只能有一个父类
3)子父类是相对的概念。
4)子类直接继承的父类,称为:直接父类。间接继承的父类称为间接父类
5)子类继承父类以后,就获取了直接父类以及所有简介父类中声明的属性和方法
4.
1)如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
2)所有的java类(除java.lang.Object类之外)都直接或间接地继承于java.lang.Object类
3)意味着,所有的java类都具有java.lang.Object类声明的功能
5.练习:
1)
package com.atguigu.exer; public class ManKind { int sex; int salary; public ManKind() { } 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 if(salary != 0){ System.out.println("job"); } } }
package com.atguigu.exer; public class Kids extends ManKind{ int yearsOld; public void printAge() { System.out.println(yearsOld); } }
package com.atguigu.exer; public class KidsTest { public static void main(String[] args) { Kids someKid = new Kids(); someKid.salary = 10000; someKid.sex = 1; someKid.yearsOld = 12; someKid.manOrWoman(); someKid.employeed(); someKid.printAge(); } }
2)
*.Ecilipse中Debug功能的使用
1.System.out.println();
2.设置断点
Debug调试,step into是进入方法中
step over 执行下一行代码
terminate停止
resume进行到下一个断点处,若再无断点,则再执行resume时debug停止
drop to frame返回到方法的初始行
5 - 2 方法的重写(Override/Overwrite)
1.重写:
子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:
重写以后,当创建子类对象以后,通过子类对象调用父类中的同名同参数的方法时,实际执行的是子类重写父类的方法
3.重写的规定:
方法的声明: 权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型{
}
约定俗称:子类中叫重写的方法;
父类中叫被重写的方法:
① 子类重写的方法名和形参列表与父类被重写的方法名和形参列表相同
② 子类重写方法的权限修饰符要不小于父类被重写的方法的权限修饰符
>特殊情况:子类不能重写父类中private权限的方法
③ 返回值类型
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型也是void
>父类被重写的方法的返回值类型是A类,则子类重写方法的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型如果是基本数据类型,则子类重写的方法的返回值类型一定是相同的基本数据类型
④ 子类重写的方法抛出的异常类型,不大于父类被重写的方法抛出的异常类型
************************************
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)
*.区分:方法的重载和重写
5 - 3 四种访问权限修饰符
5 - 4 super关键字
1.super介绍
1)super可以理解为:父类的
2)super可以用来调用:属性、方法、构造器
2.super关键字的使用
1)我们可以在子类的方法或构造器中,通过使用"super.属性"或"super.方法"的方式,显式的调用父类中的属性或方法。但是,通常情况下,我们习惯省略"super.
2)特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的时父类中声明的属性。
3)特殊情况:当子类和父类中定义了同名的方法时,我们要想在子类中调用父类中声明的方法,则必须显式的使用"super.方法"的方式,表明调用的时父类中声明的方法。
3.super调用构造器
public Student(String name,int age,String major)
{
super(name,age);
this.major = major;
}
1)我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类声明的指定的构造器
2)"super(形参列表)"的使用,必须声明在子类构造器的首行!
3)我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一;
4)在类的构造器中,既没有显式的声明this(形参列表)或者super(形参列表),则默认调用的是父类中空参的构造器
5)在类的多个构造器中,至少有一个类的构造器中使用了"super(类型列表)"
5 - 5 子类对象实例化的过程
1)从结果上看:
子类继承父类以后,就获取了父类对象声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
2)从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接地调用其父类的构造器,进而调用其父类的父类的构造器,直到调用了java.lang.Object中的空参构造器位置。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行使用
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
5 - 6 面向对象特征之三:多态性
一、
1)理解多态性:
可以理解为一个事务的多种形态。多态是运行时行为
2)何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3)多态的使用:
(虚拟方法调用)
我们在编译期,只能调用父类中声明的方法,但在运行期,实际运行子类重写父类的方法
编译看左边,运行看右边
4)多态性的使用前提:
1)类的继承关系
2)方法的重写
5)对象的多态性,只适用于方法,不适用于属性
说明:
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型
编译时,只能调用父类中声明的方法,子类特有的属性和方法不能调用
二、向下转型
(使用强制类型转换符)
调用子类特有的属性和方法:
Man m1 = (Man)p2;
使用强转时,可能出现ClassCastException的异常
三.instanceof关键字的使用
1.使用情境:
为了在避免在向下转型是出现ClassCastException的异常,我们在向下转型之前,进行instanceof的判断:一旦返回true,若不是返回false
2.使用方法
a instanceof A :判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false
3.拓展
如果a instanceof A返回true,则 a instanceof B 也返回true.
其中,类B是类A的父类
*.虚拟方法调用
*.理解
package com.atguigu.exer; class Base{ int count = 10; public void display() { System.out.println(this.count); } } class Sub extends Base{ int count = 20; public void display() { System.out.println(this.count); } } public class FieldMethodTest { public static void main(String[] args) { Sub s = new Sub(); System.out.println(s.count);//20 s.display();//20 Base b = s; //==,对于引用数据类型来讲,比较的的是两个引用数据类型变量的地址值是否相同 System.out.println(b == s);//true System.out.println(b.count);//10 b.display();//20 } }
四、练习
package com.atguigu.exer1; public class GeometricObject { protected String color; protected double weight; public GeometricObject(String color , double weight) { this.color = color; this.weight = weight; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public double findArea(){ return 0.0; } }
package com.atguigu.exer1; public class Circle extends GeometricObject{ private double radius; public Circle(String color, double weight, double radius) { super(color,weight); this.radius = radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } public double findArea() { return 3.14*radius*radius; } }
package com.atguigu.exer1; public class MyRectangle extends GeometricObject{ private double width; private double height; public MyRectangle(String color, double weight, double width, double height) { super(color,weight); this.width = width; this.height = height; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public double findArea() { return width * height; } }
package com.atguigu.exer1; public class GeometricTest { public static void main(String[] args) { GeometricTest test = new GeometricTest(); Circle circle = new Circle("红色",152.0,4.0); MyRectangle myRectangle = new MyRectangle("蓝色", 152.0, 4.0, 5.0);//先创建子类对象 boolean isEqual; circle.setRadius(5.0); //若要使用多态性,则创建新对象,并指向原子类对象 GeometricObject circle1 = circle; GeometricObject myRectangle1 = myRectangle;//创建好用于多态的对象 isEqual = test.equalsArea(circle1, myRectangle1); System.out.println(isEqual); test.displayGeometricObject(circle); } public boolean equalsArea(GeometricObject geo1,GeometricObject geo2) { if(geo1.findArea() == geo2.findArea()) { return true; }else{ return false; } } public void displayGeometricObject(GeometricObject geo) { System.out.println("图形的面积为:" + geo.findArea()); } }
五、总结
因为多态性的对象只能使用子类和父类共有的方法(即子类重写父类的方法),所以我们在使用多态性之前,正常创建子类对象,对子类对象进行操作,若要使用多态性,则再创建多态性的对象,并且将原对象赋值给新对象,进行多态性操作(或者直接给父类形参传子类对象)。
要注意,因为我们创建的多态对象和原对象使用的是一个地址值,所以我们无论修改的是多态对象还是原对象,对象的对应属性均发生改变,只是说,在多态情况下,原对象的部分属性和功能被隐藏,不能被多态对象直接调用
5 - 7 Object类的使用
一.说明:
1.Object类是Java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类为其父类
3.Object类中的功能(属性、方法)据有通用性。
4.Object类中只定义了一个空参构造器
二、类的内容
属性:无
方法:equals() / toString() / getClass / hashCode() / clone() / finalize() / wait() / notify() / notifyAll()
三、equals使用
1.== 和 equals()的区别
补充: == 符号使用时,必须保证左右两边符号一致
2.重写equals()方法
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同。那么,我们就需要对Object类中的equals()方法进行重写
重写原则:
比较两个对象的实体内容是否相同
public boolean equals(Object obj) { if(this == obj) { return true; } if(obj instanceof Customer) { Customer cust = (Customer)obj; //比较两个对象的属性是否都相同 return this.age == cust.age && this.name.equals(cust.name); } return false; }
实际开发中equals()方法一般自动生成
3.练习
四、toString的使用
1.使用
1)当我们输出一个对象的引用时,实际上就是调用toString()
2)Object类中toString()的定义:
public String toString(){ return getClass().getName + "@" + Integer.toHexString(hashcode()); }
3)像String/Date/File/包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"的信息。
4)自定义类也可以重写toString()方法。当调用此方法时,返回对象的实体内容
2.练习
5 - 8 包装类的使用
1.单元测试方法的使用
步骤:
1.选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步
2.创建Java类,进行单元测试。
此时的Java类要求:①此类是public的 ②此类提供公共的无参构造器。
3.此类中声明的单元测试方法。
此时的单元测试方法:方法的权限是public,没有返回值,没有形参
4.此单元测试方法上需要声明注解:@test,并在单元测试类中import org.junit.Test
5.声明好单元测试方法以后,就可以在方法体内测试相关的代码
6.写完代码以后,双击单元测试方法名:右键 :run as - JUint Test
说明:
1.如果执行结果没有任何异常:绿条
2.包装类
3.基本数据类型,包装类和String类型的转换
1)基本数据类型、String类型 --> 包装类:
调用包装类的构造器
@Test public void test1() { int num1 = 10; Integer in1 = new Integer(num1); System.out.println(in1.toString()); Integer in2 = new Integer("123"); System.out.println(in2.toString()); Float f1 = new Float(12.3f); Float f2 = new Float("12.3"); System.out.println(f1); System.out.println(f2); Boolean b1 = new Boolean(true); Boolean b2 = new Boolean("true"); Boolean b3 = new Boolean("true123"); System.out.println(b3);//false }
2)包装类 --> 基本数据类型:
调用包装类的xxxValue
@Test public void test2() { Integer in1 = new Integer(12); int i1 = in1.intValue(); System.out.println(i1 + 1); }
JDK 5.0新特性:
*.自动装箱与自
动拆箱
@Test public void test3() { int num1 = 10; method(num1);//自动装箱 int num2 = 10; Integer in1 = num2;//自动装箱 //自动拆箱 int num3 = in1; } public void method(Object obj) { }
3)基本数据类型、包装类 ---> String类型
@Test public void test4() { int num1 = 10; //方式一: String str1 = num1 + ""; //方式2:调用String重载的valueOf(Xxx xxx) float f1 = 12.3f; String str2 = String.valueOf(f1); Double d1 = new Double(12.4); String str3 = String.valueOf(d1); System.out.println(str2); System.out.println(str3); }
4)String类型 ---> 基本数据类型、包装类:
调用包装类的parseXxx()方法
// 4)String类型 ---> 基本数据类型、包装类: // 调用包装类的parseXxx()方法 @Test public void test5() { String str1 = "123"; int num1 = Integer.parseInt(str1); System.out.println(num1 + 1); String str2 = "true"; boolean b1 = Boolean.parseBoolean(str2); System.out.println(b1); }
4.包装类面试
public class InterviewTest { @Test public void test1() { Object o1 = true ? new Integer(1): new Double(2.0); System.out.println(o1);//1.0 // 先运用多态性,注意三元运算在编译时, //会将两个类型自动提升为相同类型,最后输出时自动拆箱,输出编译后的值1.0 } @Test public void test3() { Integer i = new Integer(1); Integer j = new Integer(1); System.out.println(i == j);//false //Integer内部定义了IntegerCache结构,定义了Integer[]数组 //保存了从-128 ~ 127范围内的整数。如果我们使用自动装箱的方式 //给Integer赋值的范围在 -128 ~ 127范围内时,可以直接使用数组中的元素, //不用再去new了。目的:提高效率 Integer m = 1; Integer n = 1; System.out.println(m == n);//true Integer x = 128;//相当于new了一个Integer对象 Integer y = 128; System.out.println(x == y);//false } }
5.包装类练习
package com.atguigu.exer4; import java.util.Vector; import java.util.Scanner; public class ScoreTest { public static void main(String[] args) { //1.实例化Scanner,用于从键盘获取学生成绩; Scanner scan = new Scanner(System.in); //2.创建Vector()对象 Vector v = new Vector(); //3.通过for(;;)或while(true)给Vector中添加数据 int maxScore = 0; for(;;) { System.out.println("请输入学生成绩(以负数代表结束):"); int score = scan.nextInt(); if(score < 0) { break; } if(score > 100) { System.out.println("输入的成绩非法!"); continue; } v.addElement(score);//自动装箱 if(maxScore < score)//获取学生成绩的最大值 { maxScore = score; } } //4.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个同学的等级 char level; for(int i = 0;i < v.size();i++) { Object obj = v.elementAt(i); int score = (Integer)obj;//自动拆箱 /* * Integer inScore = (Integer)obj; * int score = inScore.intValue(); * */ if(maxScore - score <= 10) { level = 'A'; }else if(maxScore - score <=20) { level = 'B'; }else if(maxScore - score <=30) { level = 'C'; }else { level = 'D'; } System.out.println("student- " + i + " score:" + score + ",level is:" + level ); } } }