Java基础09-面向对象(4)【多态】
面向对象4 1 多态 1.1 概述
是指同一行为,具有多个不同表现形式。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
1.2 概念及语法
概念
多态性,是面向对象中最重要的概念,在Java中的体现:父类的引用指向子类的对象
Java编译器将. java文件编译成. class文件时,变量的类型
Java虚拟机将,class文件加载进内存,真正创建的对象所属的类型,运行时类型
语法格式
父类类型 引用 = new 子类对象;
引用.方法名();
示例代码
public abstract class Animal { public abstract void eat();
}class Cat extends Animal { public void eat() { System.out.println("吃鱼"); }
}class Dog extends Animal { public void eat() { System.out.println("吃骨头");}
}public class Test { public static void main(String[] args) { // 多态形式,创建对象Animal a1 = new Cat(); // 调用的是 Cat 的 eat a1.eat(); // 多态形式,创建对象 Animal a2 = new Dog(); // 调用的是 Dog 的 eat a2.eat();}
}
1.3 实现原理
1需要存在继承或者实现关系
2有方法的重写
多态最重要的特性:发生多态时,父类引用调用的方法是子类重写的方法。
虚拟方法调用( )
正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
多态情况下
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。这也叫做方法的动态绑定
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法 //虚拟方法的调用
编译时类型和运行时类型
编译时e为类型,而方法的调用是在运行时确定的,所以调用的是类的()方法。——动态绑定
内存图
属性不具有多态性
1.4 多态的好处 1.5 操作符
=new Cat();
.out.( Cat); //true
.out.( Dog); //flase
.out.( ); //true
x A:检验x是否为类A的对象,返回值为型。 //X对象是否是A类型
1.6 对象类型转换
int b;
a= b;
byte c=(byte) b; //精度丢失,强制类型转换。
(Cat) .run();//强制转换
(Gog) .rin();//强制转换
对Java对象的强制类型转换称为造型()
示例代码
public class Test {public void method(Person e) { // 设Person类中没有getschool() 方法// System.out.pritnln(e.getschool()); //非法,编译时错误if (e instanceof Student) {Student me = (Student) e; // 将e强制转换为Student类型System.out.pritnln(me.getschool());}}public static void main(String[] args){Test t = new Test();Student m = new Student();t.method(m);}
}
课堂练习
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);//20s.display();//20Base b = s;System.out.println(b == s);//trueSystem.out.println(b.count);//10b.display();//20}
}
课堂练习-
class Person {protected String name="person";protected int age=50;public String getInfo() {return "Name: "+ name + "\n" +"age: "+ age;}
}class Student extends Person {protected String school="pku";public String getInfo() {return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school;}
}class Graduate extends Student{public String major="IT";public String getInfo(){return "Name: "+ name + "\nage: "+ age + "\nschool: "+school+"\nmajor:"+major;}
}
建立InstanceTest类,在类中定义方法method(Person e);
在method中:
(1)根据e的类型调用相应类的getInfo()方法。
(2)根据e的类型执行:
如果e为Person类的对象,输出:
“a person”;
如果e为Student类的对象,输出:
“a student”
“a person ”
如果e为Graduate类的对象,输出:
“a graduated student”
“a student”
“a person”package Stage1_JavaBasics.Chapter02_ObjectOriented.ObjectOriented04.class01;public class InstanceTest {public void method(Person e){if (e instanceof Graduate){System.out.println("a graduated student \na student\na person\n");}else if (e instanceof Student){System.out.println("a student \na person\n");}else if(e instanceof Person){System.out.println("a person\n");}}public static void main(String[] args) {Person person=new Person();person.getInfo();Student student=new Student();student.getInfo();Graduate graduate=new Graduate();graduate.getInfo();InstanceTest text=new InstanceTest();text.method(person);text.method(student);text.method(graduate);}
}
课堂练习-
定义三个类,父类GeometricObject代表几何形状,子类Circle代表圆形,MyRectangle代表矩形。定义一个测试类GeometricTest,编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
练习题
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();}}
2 代码块
代码块(或初始化块)的分类:
代码块通常用于初始化的属性
class Person { public static int total; static {total = 100;//为total赋初值}…… //其它属性或方法声明 }
示例代码
class Person {public static int total = 100;static {total = total + 50;System.out.println("in static block!");}
}public class PersonTest {public static void main(String[] args) {System.out.println("total = " + Person.total);System.out.println("total = " + Person.total);}
}
3 类 3.1 介绍
public class Person {
...
}
等价于:
public class Person extends Object {
...
}
3.2 主要结构
3.3 ()方法
如果要自定义对象相等的判断逻辑,就需要重写()方法
( obj){
if (obj ) {
this.name == ( () obj ) . name;
} else {
false;
}
特例:当用()方法进行比较时,对类File、、Date及包装类( Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象;
当自定义使用()时,可以重写。用于比较两个对象的“内容”是否都相等
重写()方法的原则
面试题:==和的区别
==既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址
的话,它是属于java.lang.类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到等类的方法是被重写过的,而且类在日常开发中** 用的比较多,久而久之,形成了是比较值的错误观点。
具体要看自定义类里有没有重写的方法来判断。
通常情况下,重写方法,会比较类中的相应属性是否都相等。
课堂练习
int it = 65;
float fl = 65.0f;
System.out.println(“65和65.0f是否相等?” + (it == fl));//true
char ch1 = 'A'; char ch2 = 12;
System.out.println("65和'A'是否相等?" + (it == ch1));//true
System.out.println(“12和ch2是否相等?" + (12 == ch2));//true
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("str1和str2是否相等?"+ (str1 == str2));//false
System.out.println("str1是否equals str2?"+(str1.equals(str2)));//true
System.out.println(“hello” == new java.util.Date());
课堂练习-
编写Order类,有int型的orderId,String型的orderName,相应的getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。
3.4 ()方法
.:是前面的那一部分
4.包装类
(基本数据类型-字符串-包装类 三者类之间的相互转换)
基本数据类型
//每一个基本数据类型提供个对应的包装类
class {
void main([] args) {
int i=10; //Ruby int i=10;i.
= new
(i);
// 方法根据要返回的基本数据类型将value转化成该类型返回,返回的是基本数据类型。
long l = . ();
//方法将字符串解析为对应的值。
long il= .(“67”);
//方法将字符串解析为对应的对象。
2 = .(“67”);
//常用 //方法将字符串或者是基本数据类型解析然后包装成对应的包装类对象
= . (78);
//
int bytes = .BYTES;
. out . (bytes);
基本数据类型和其对应的包装类的转换
1.1基本转包装
=new (“23.9f”)
Float =Float . va lue0f (45.7f)
1.2包装转基本
d = . ():
1.3自动装箱和自动拆箱
Java的编译器会根据需要自动地在基本数据类型和其对应的包装类之问进行转化
= new ( value: 10);
= new ( value: 20);
//add(20, 67); //自动装箱,将基本数据类型转换成包装类型
int sum = + ; //自动拆箱,将包装类型拆成基本数据类型
. out. (sum);
2字符串与包装类之间的转换
2.1字符串->包装类
= new
( S: “23.9”);
FLoat = Float . va Lue0f(“45.7f”);
2.2包装类->字符串
(1) s = . ();
3字符串与基本数据类型的转换
3.1字符串–>基本数据类型
(1)int i = . ( “36F”);
3.2基本数据类型–>字符串
(1) s = . (i);
. out . (s);
(2) s1=i+“ ”;
. out. (s1);
思考题
1. ol = true ? new ( value: 1) : new ( value: 2.0) ;
// 对象 对象
// int 1 2.0
// 1. 0 2. 0
问题:. out. (o1);?
A 1 B 2 C 1.0 D 其他
选c1.0
i =new ( value: 1);
j = new ( value: 1) ;
. out.(i == j);//
m = 1;
n = 1;
.out. (m == n);//true,放到缓存中-128~127
x = 128;
y = 128;
. out .(x == y);//,放到缓存中-128~127,超出,只能在内存中new对象
5 接口 5.1 概述
5.2 语法
命名:表示什么能力时:
定义Java类的语法格式:先写,后写
class SubClass extends SuperClass implements InterfaceA{ }
一个类可以实现多个接口,接口也可以继承其它接口。 //–> ,
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
接口的主要用途就是被实现类实现。(面向接口编程)
与继承关系类似,接口与实现类之间存在多态性
接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前),而没有变量和方法的实现。
5.3 接口与抽象类
9.都可以使用:没有成员变量
思考题-
interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
System.out.println(x);//对x的引用不明确 B和A都匹配
}
public static void main(String[] args) {
new C().pX();
} }
思考题采纳-
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable,
Bounceable {
Ball ball = new Ball("PingPang");
}class Ball implements Rollable {
private String name;
public String getName() {
return name; }
public Ball(String name) {
this.name = name; }
public void play() {
ball = new Ball("Football"); //无法为最终变量球赋值
System.out.println(ball.getName());
} }
课堂练习-
定义一个接口用来实现两个对象的比较。
interface CompareObject{public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
定义一个Circle类,声明redius属性,提供getter和setter方法
定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小。
思 考 : 参 照 上 述 做 法 定 义 矩 形 类 Rectangle 和 ComparableRectangle 类 , 在ComparableRectangle类中给出compareTo方法的实现,比较两个矩形的面积大小。
5.4 接口的改进
Java 8中,可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
6 内部类
内部类:在一个类的内部定义得类
6.1 概述
分类:
成员内部类作为类的成员的角色:
成员内部类作为类的角色:
注意
非的成员内部类中的成员不能声明为的,只有在外部类或的成员内部类中才可声明成员。
外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
成员内部类可以直接使用外部类的所有成员,包括私有的数据
当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
示例代码
class Outer {private int s;public class Inner {public void mb() {s = 100;System.out.println("在内部类Inner中s=" + s);} }public void ma() {Inner i = new Inner();i.mb();}
}public class InnerTest {public static void main(String args[]) {Outer o = new Outer();o.ma();}
}
6.2 内部类的使用语法
如何实例化成员内部类
如何在成员内部类中调用外部类的结构
//创建Dog实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类):
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
1.在外部类的内部结构中使用 //在外部方法中new()
= car.new ();
2.在外部类 //在外部main中new();
//如果内部类是一个非静态的结构,那么就不能直接在外部直接实例化
Car car = new Car() ;
= car.new ();
//如果内部类是一个静态()的结构,那么就不能直接在外部直接实例化
Car. = new Car.( );
. start();
6.3 匿名内部类
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
格式:
new 父类构造器(实参列表)|实现接口(){ //匿名内部类的类体部分 }new Animal(){// 方法重写
}
匿名内部类的特点
示例代码
interface A{public abstract void fun1();
}public class Outer{public static void main(String[] args) {new Outer().callInner(new A(){//接口是不能new但此处比较特殊是子类对象实现接口,只不过没有为对象取名public void fun1() {System.out.println(“implement for fun1");}});// 两步写成一步了}public void callInner(A a) {a.fun1();}
}
1.具名类的具名对象
Cat cat=new Cat();
2.具名类的匿名对象
new Cat(); //作用使用一次就完了
3.匿名类的具名对象(一般是抽象类或者是接口的实现类) //几何类是抽象类,不能创建对象
gb=new ( ){
@
() {
0;
};
4.匿名类的匿名对象
new ( ){
@
() {
0;
}.();