------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
面向对象(3)
主要内容:《 Math类的随机数、代码块、继承、this和super、方法重写的应用、方法重写、final关键字、多态 》
1 学习Math类的随机数功能
通过帮助文档:
1.Math类是在:java.lang包下,不需要导包(关于包,后面会学习);
2.此类没有构造方法,所有的可用方法都是static;通过类名就可以调用;
3.要学习使用:random()方法;
形参:没有
返回值:double。这个值:大于等于0.0并且小于1.0
1.获取1--100之间的随机数:
(int)(随机数 * 100) + 1
1 class Demo { 2 public static void main(String[] args) { 3 for(int i = 0;i < 10 ;i++){ 4 System.out.println("获取一个随机数:" + Math.random()); 5 } 6 System.out.println("*****获取10个1--100的随机数*****"); 7 for(int i = 0;i < 10 ;i++){ 8 System.out.println("第:" + (i + 1) + " 个:" + ((int)(Math.random() * 100) + 1)); 9 } 10 } 11 }
2 猜数字小游戏案例
猜商品价格:
1.系统先生成一个1--1000的一个整数值,作为一个商品价格;
2.用循环结构实现用户猜数;
3.每次循环做什么?
1).接收用户的猜的数字;
2).跟我们生成的数字进行判断,提示:高了,低了,相等
3).如果高了,或低了:继续下一次;
如果相等:结束循环
import java.util.Scanner; class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //1.系统先生成一个1--1000的一个整数值,作为一个商品价格; int num = (int)(Math.random() * 1000) + 1; System.out.println("1--1000的商品价格已经生成,可以开始了......"); //2.用循环结构实现用户猜数; while(true){ System.out.print("你猜的数字:" ); int n = sc.nextInt(); //跟我们生成的数字进行判断,提示:高了,低了,相等 if(n > num){ System.out.println("高了!"); }else if( n < num){ System.out.println("低了!"); }else{ System.out.println("恭喜您猜中!价格为:" + num); break; } } } }
3 代码块的概述和分类
代码块:
1.我们可以将一些代码封装到一对大括号中,这就叫:代码块。
{
//代码内容
}
2.代码块的分类:
1).局部代码块:在某个方法内,或某个语句内,出现的一对大括号,里面的代码就是代码块;
1 public static void main(String[] args){ 2 { 3 //局部代码块 4 int num = 10; 5 if(num>=10){ 6 } 7 while(true){ 8 } 9 } 10 //大家以前写程序时,一个常见的问题: 11 if(num >= 10); 12 { 13 } 14 }
2).构造代码块:定义在"类体中";在实例化对象时,被执行。
如果有构造方法同时存在,它会先于构造方法被执行;
它的作用同构造方法,就是用来初始化数据成员,或做一些先期的准备工作;
3).静态代码块:定义在"类体中";使用static关键字;
当第一次实例化此类对象时,会被执行一次;之后不会再被执行;
如果构造方法、普通代码块、静态代码块同时存在,那么执行顺序:
静态代码块-->普通代码块-->构造方法;
构造代码块虽然与构造方法的作用相同,但不能接收参数;
1 class Student 2 { 3 String name; 4 Student(){ 5 System.out.println("Student的构造方法"); 6 } 7 { 8 System.out.println("Student的构造代码块 name = " + name); 9 } 10 static{ 11 // System.out.println("Student的静态代码块 name = " + name);//编译错误,静态的只能访问静态的; 12 System.out.println("Student的静态代码块"); 13 } 14 15 } 16 class Demo 17 { 18 public static void main(String[] args) 19 { 20 Student stu = new Student(); 21 System.out.println("**************************"); 22 Student stu1 = new Student(); 23 System.out.println("**************************"); 24 Student stu2 = new Student(); 25 } 26 }
4 继承的引入和概述以及案例演示
学生类:
属性:
学员编号:
姓名:(去掉)
性别:(去掉)
年龄:(去掉)
行为:
学习();
教师类:
属性:
老师编号:
姓名:(去掉)
性别:(去掉)
年龄:(去掉)
行为:
教学();
当设计好后,我们发现学生类和教师类中都包含了很多"重复"的元素:
String name;
int age;
char sex;
我们可以将这些重复的内容,进行进一步的抽取,再定义一个类,将这些共性的内容放到这个新类中,
之后让我们的学生类和教师类去"继承"那个新类。这时,我们的学生类和教师类中就不需要定义那些
重复的内容,继承后,将会从"父类"中继承。
进行抽取,定义新类:
人员类:
姓名:
性别:
年龄:
继承:
1.当一个类需要继承自另一个类时,使用关键字:extends
2.当一个类继承了某个类之后: 继承方:子类(派生类)
被继承方:父类(超类、基类)
3.当子类继承了父类后,就自动拥有了父类中允许被继承的成员:包括成员变量、成员方法。
继承的好处:
1.被子类继承后,达到了一个"代码重用"的目的;
2.为后面的"多态"提供了一个前提;
1 class Person 2 { 3 String name; 4 int age; 5 char sex; 6 } 7 class Student extends Person 8 { 9 String stuNo; 10 void study(){ 11 System.out.println("我们学习Java"); 12 } 13 } 14 class Teacher extends Person 15 { 16 String teaNo; 17 18 void teach(){ 19 System.out.println("我们教Java"); 20 } 21 } 22 class Employee extends Person 23 { 24 String empNo; 25 26 } 27 class Demo 28 { 29 public static void main(String[] args) 30 { 31 Student stu = new Student(); 32 stu.stuNo = "it001";//Student自有的 33 stu.name = "刘德华";//继承的 34 stu.age = 20;//继承的 35 stu.sex = ‘男‘;//继承的 36 System.out.println(stu.stuNo + "," + stu.name + "," + stu.age + "," + stu.sex); 37 } 38 }
5 继承的好处和弊端
继承的好处:
1.提高了代码的复用性;
2.提高了代码的可维护性;由于共性的内容被抽取到一个类中,如果放生更改,只需改父类一处即可;
继承的弊端:
1.一旦两个类具有了"子父关系",也就意味着有了"依赖关系"。子类依赖于父类。
当Student继承了Person后,Student就对Person产生了依赖,必须要有Person的存在,Student
才能编译通过。
6 Java中类的继承特点
Java中继承的特点:
1.Java只允许单继承:一个类只能继承自一个类;一个儿子只能有一个爹;
2.Java允许多级继承:Z继承自Y,Y继承自X;Z就拥有了Y 和X中允许被继承的成员;
class A{ void fun(){ System.out.println("A"); } } class B{ void method(){ } void fun(){ System.out.println("B"); } } /* class C extends A,B//编译错误。Java只允许单继承{ //被继承的fun()方法将产生冲突 }
1 //多级继承: 2 class X 3 { 4 int numx = 10; 5 } 6 class Y extends X 7 { 8 int numy = 20; 9 } 10 class Z extends Y 11 { 12 } 13 class Demo 14 { 15 public static void main(String[] args) 16 { 17 Z z = new Z(); 18 System.out.println(z.numx + "," + z.numy); 19 } 20 }
7 继承的注意事项和什么时候使用继承
继承的注意事项:
1.子类只能继承父类所有非私有的成员(成员方法和成员变量):
2.子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
3.不要为了部分功能而去继承;
什么时候使用继承:
当"子类"相对于"父类"为"is a(是一个)"的关系时,可以使用继承:
我们说:Student是一个Person,就可以继承自Person
8 继承中类和类之间的关系(UML)
类和类之间的关系:
1."is a"(是一个):常见的就是"继承";
class Person{}
class Student extends Person{}
2."has a"(有一个):
class 学生{}
class 老师{}
//教室里面有:一个"老师",80名"学生"
class 教室{
int 楼层;//自有的属性
int 面积;//自有的属性
老师 tea = new 老师();//"老师"的对象最为"教室"的成员属性
学生[] stuArray = new 学生[80];//"学生"数组作为"教室"的成员属性
}
3."组成关系":一个类中没有"自有成员",全部都是其它的"类类型",由其它"类"组成的;
class CPU{}
class 硬盘{}
class 主板{}
.....
//"电脑"类全部都是由其它"类"组成
class 电脑{
CPU cpu;
硬盘 yp;
主板 zb;
....
}
4."依赖关系(关联关系)":
class 学生{}
class 老师{}
class 校长{
void talk(学生 xs){//由于talk方法接收的是"学生"类型的对象,我们说:"校长类"依赖于"学生类"
}
void talk(老师 ls){
}
}
9 继承中成员变量的关系
继承中成员变量的关系:
1.父类中的成员会被子类继承;
1 class Fu 2 { 3 int num = 10000; 4 } 5 class Zi extends Fu 6 { 7 int num = 100;//子类的成员变量,覆盖了父类中同名的成员变量 8 9 //在Zi类内部访问num 10 void show(){ 11 int num = 10; 12 class Demo { 13 public static void main(String[] args) { 14 Zi z = new Zi(); 15 System.out.println(z.num);//在"Zi类"的外部访问num 16 System.out.println("******访问show()*********"); 17 z.show(); 18 } 19 } 20 System.out.println("num = " + num);//10:就近原则。先找"局部变量"-->"成员变量" --> "父类" System.out.println("本类的num : " + this.num);//本类的num:先在"本类"找,如果没有,会去"父类"找 21 System.out.println("访问父类的num :" + super.num);//访问父类的num 22 }}
10 this和super的区别和应用
super和this关键字:
1.super 1).在子类中使用;
2).存储的是"父类的引用";它指向父类对象空间;
3).在子类中,使用super可以访问父类的:成员变量、成员方法、构造方法
在子类中调用父类成员:
1 成员变量: 2 class Fu{ 3 int num = 10; 4 } 5 class Zi extends Fu{ 6 void show(){ 7 System.out.println(super.num); 8 }} 9 成员方法: 10 class Fu{ 11 void fun1(){ System.out.println("Fu-->fun1()"); 12 } 13 } 14 calss Zi extends Fu{ 15 void show(){ 16 super.fun1();//调用父类的成员方法; 17 } 18 } 19 调用父类的构造方法: 20 class Fu{ 21 } 22 class Zi extends Fu{ 23 Zi(){ 24 super();//调用父类无参的构造方法; System.out.println("Zi的构造方法"); 25 } 26 }
4).有一种情况,子类必须显示的使用super()调用父类的构造方法:
当父类没有"无参构造方法"时;
1.当实例化子类对象时,Java回去实例化它的父类-->默认调用父类"无参构造方法";
2.如果父类没有"无参构造方法",那么Java 就没有办法调用;
3.这时,子类必须显示的使用super(),告诉Java编译器,调用哪个带参的构造方法,并传递什么样的参数;
5).当使用super调用父类的构造方法时,必须写在这个构造方法的:第一句有效代码;
this: 1).任何类中都可以使用;
2).存储的"本类对象的引用";它指向的本类对象的空间;
3).this可以访问本类对象的:成员变量、成员方法、构造方法
this访问本类成员:
1 成员变量: 2 class Student{ 3 String name; 4 void show(){ System.out.println(this.name); 5 } 6 } 7 成员方法: 8 class Student{ 9 void f1(){ 10 } 11 void f2(){ 12 this.f1();//调用本类的方法 13 } 14 } 15 构造方法 16 class Student{ 17 Student(){ 18 System.out.println("无参的构造方法"); 19 } 20 Student(int n){ 21 Student();//掉用本类其它构造方法。不可以这样调用。 22 this();//调用本类无参的构造方法; System.out.println("带参的构造方法"); 23 } 24 } 25 4).调用本类其它构造方法使用this()。可以带参数。 26 注意:this()语句,必须是这个构造方法的第一条有效语句;
1 class Fu 2 { 3 String name; 4 Fu(String name){ 5 this.name = name; 6 System.out.println("Fu的构造方法"); 7 } 8 void show(){ 9 System.out.println("Fu-->show()"); 10 } 11 } 12 class Zi extends Fu 13 { 14 Zi(){ 15 super("匿名"); 16 } 17 Zi(String name){ 18 //直接传给了父类。子类必须显示的使用super调用父类的带参的构造方法。否则编译错误; 19 super(name); 20 // this();//注意:super()和this()语句不能同时存在; 21 System.out.println("Zi的构造方法"); 22 23 } 24 void fun(){ 25 super.show();//可以通过super关键字访问父类的成员方法; 26 } 27 } 28 class Demo 29 { 30 public static void main(String[] args) 31 { 32 Zi z = new Zi(); 33 34 } 35 }
11 this和super以及重写和重载的面试题
super和this关键字:
1.super:
1).在子类中使用;
2).存储的是"父类的引用";它指向父类对象空间;
3).在子类中,使用super可以访问父类的:成员变量、成员方法、构造方法
在子类中调用父类成员:
1 成员变量:class Fu{ 2 int num = 10; 3 } 4 class Zi extends Fu{ 5 void show(){ System.out.println(super.num); 6 }} 7 成员方法: 8 class Fu{ 9 void fun1(){ 10 System.out.println("Fu-->fun1()"); 11 }} 12 calss Zi extends Fu{ 13 void show(){ 14 super.fun1();//调用父类的成员方法; 15 }} 16 调用父类的构造方法: 17 class Fu{ 18 } 19 class Zi extends Fu{ 20 Zi(){ 21 super();//调用父类无参的构造方法; 22 System.out.println("Zi的构造方法"); 23 } 24 }
4).有一种情况,子类必须显示的使用super()调用父类的构造方法:
当父类没有"无参构造方法"时;
1.当实例化子类对象时,Java回去实例化它的父类-->默认调用父类"无参构造方法";
2.如果父类没有"无参构造方法",那么Java 就没有办法调用;
3.这时,子类必须显示的使用super(),告诉Java编译器,调用哪个带参的构造方法,并传递什么样的参数;
5).当使用super调用父类的构造方法时,必须写在这个构造方法的:第一句有效代码;
this:
1).任何类中都可以使用;
2).存储的"本类对象的引用";它指向的本类对象的空间;
3).this可以访问本类对象的:成员变量、成员方法、构造方法this访问本类成员:
1 void f2(){ 2 this.f1();//调用本类的方法 3 } 4 } 5 构造方法 6 class Student{ 7 Student(){ 8 System.out.println("无参的构造方法"); 9 } 10 Student(int n){ 11 // Student();//掉用本类其它构造方法。不可以这样调用。 12 this();//调用本类无参的构造方法; 13 System.out.println("带参的构造方法"); 14 } 15 } 16 成员变量: 17 class Student{ 18 String name; 19 void show(){ 20 System.out.println(this.name); 21 } 22 } 23 成员方法: 24 class Student{ 25 void f1(){} 26 void f2(){ 27 this.f1();//调用本类的方法 28 } 29 } 30 构造方法 31 class Student{ 32 Student(){ 33 System.out.println("无参的构造方法"); 34 } 35 Student(int n){ 36 // Student();//掉用本类其它构造方法。不可以这样调用。 37 this();//调用本类无参的构造方法; 38 System.out.println("带参的构造方法"); 39 } 40 }
4).调用本类其它构造方法使用this()。可以带参数。
注意:this()语句,必须是这个构造方法的第一条有效语句;
class Fu{ String name; Fu(String name){ this.name = name; System.out.println("Fu的构造方法"); } void show(){ System.out.println("Fu-->show()"); } } class Zi extends Fu{ Zi(){ super("匿名"); } Zi(String name){ //直接传给了父类。子类必须显示的使用super调用父类的带参的构造方法。否则编译错误; super(name); // this();//注意:super()和this()语句不能同时存在; System.out.println("Zi的构造方法"); } void fun(){ super.show();//可以通过super关键字访问父类的成员方法;} } class Demo { public static void main(String[] args) { Zi z = new Zi(); } }
12 方法重写的应用
1.子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法重写(复写);
2.重写的格式:
1).返回值类型 方法名 ,形参列表:必须完全一致;
A."返回值类型"和"方法名"相同,"参数列表"不同:编译通过。类似于"重载"
B."方法名"和"参数列表"相同,"返回值类型"不同:编译错误。如果"方法名"和"形参列表"相同,要求"返回值类型"必须相同;
2).访问修饰符:要求:
子类的方法所具有的访问修饰符必须跟父类的方法的访问修饰符相同,或更宽的访问修饰符;
public,protected,(默认),private(从宽到窄)
1 class Fu{ 2 void show(int a){ 3 } 4 } 5 class Zi extends Fu{ 6 //编译可以通过。类似于"重载" 7 void show(String s){ 8 } 9 //编译错误。按照"重写"的格式进行要求。 10 /* 11 int show(int a){ 12 } 13 */ 14 //重写 15 public void show(int a){ 16 } 17 } 18 class Demo { 19 public static void main(String[] args) { 20 Zi z = new Zi(); 21 z.show(10);//Fu 22 z.show("刘德华");//Zi 23 } 24 }
铺垫的小知识:
第一个:成员变量有基本类型和引用类型的。
class Demo {
//基本类型
int x = 10;
//引用类型
Student s = new Student();
}
第二个:类的初始化过程
加载class文件
堆中开辟空间
变量的默认初始化
变量的显示初始化
构造代码块初始化
构造方法初始化
第三个:遇到extends,就要知道,先初始化父类数据,然后初始化子类数据。
分层初始化。
super在这里仅仅表示要先初始化父类数据。
13 继承中成员方法关系
1.子类可以覆盖父类中的同名的方法;
2.通过子类对象访问方法时:
1).先在子类中找,如果没有
2).到父类中找。
3).如果父类也没有,报错;
1 class Fu{ 2 void fun1(){ 3 System.out.println("Fu-->fun1()"); 4 } 5 } 6 class Zi extends Fu{ 7 //方法的:重写 8 void fun1(){ 9 System.out.println("Zi-->fun1()"); 10 } 11 } 12 class Demo { 13 public static void main(String[] args) { 14 Zi z = new Zi(); 15 z.fun1(); 16 } 17 }
14 方法重写的注意事项
方法重写的注意事项
1.父类中私有方法不能被重写。
2.子类重写父类方法时,访问权限不能更低。必须是具有:相同,或更宽的访问权限;
3.父类静态方法,子类也必须通过静态方法进行重写。 (其实这个算不上方法重写,但是现象确实如此,至于为什么算不上方法重写,多态中我会讲解)
class Fu{ private void show(){ System.out.println("Fu--private show()"); } public static void fun(){ System.out.println("Fu-->public static fun()"); } } class Zi extends Fu{ //可以定义跟父类相同的方法,但这不是"重写 public void show(){ System.out.println("Zi--show()"); } //子类重写父类中的静态的方法 public static void fun(){ System.out.println("Zi-->public static fun()"); } } class Demo { public static void main(String[] args) { Zi z = new Zi(); z.show(); z.fun(); //通过"子类的类名",调用父类的静态方法 Zi.fun(); } }
15 方法重写和方法重载的区别?方法重载能改变返回值类型吗?
1.Overload:重载
2.Override:重写
1.重载:在一个类中,可以定义多个同名的方法,但形参列表不完全相同;跟返回值无关;
2.重写:在子类中,可以定义跟父类一模一样的方法(返回值类型、方法名、形参列表完全相同),这时
子类的方法会覆盖父类中同名的方法。
16 this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。
1.this:
1).在任何类中使用;
2).存储的是本类对象的引用;
3).可以访问本对象的成员变量、成员方法、构造方法;
2.super:
1).在子类中使用;
2).存储的是父类对象的引用;
3).可以访问父类对象的成员变量、成员方法、构造方法;
17 final关键字
final关键字:
1.可以修饰:
1).成员变量:此变量拥有最终的值。是一个"常量"。其值是不能被修改的。或者只能被赋值一次;(也分为基本类型和引用类型)
2).成员方法:表示最终的方法。不能被"重写"。
3).类:表示最终的类;不能被"继承".
4).局部变量:
A.普通局部变量:
A-1:修饰基本数据类型:其值不能被更改;
A-2:修饰引用数据类型:其地址不能被更改;
B.方法的形参:
B-1:修饰基本数据类型:其形参的值不能被更改;
B-2:修饰引用数据类型:其形参的地址不能被更改;
1 class Person{ 2 final void show(){ 3 System.out.println("我是传智播客的一员"); 4 } 5 } 6 class Student extends Person{ 7 String name; 8 static final String SCHOOL_NAME = "传智播客--北京校区"; 9 final int num; 10 double aaa; 11 Student(){ 12 num = 20; 13 } 14 System.out.println(Student.SCHOOL_NAME); 15 // Student.schoolName = "北京校区"; 16 System.out.println(Student.SCHOOL_NAME); 17 final int num = 10;//final修饰局部变量--基本数据类型 18 System.out.println("num = " + num); 19 // num = 20;//其值不能改变 20 final Student stu = new Student();//final修饰局部变量--引用数据类型 21 //试图重写父类的final方法 22 //编译错误,无法覆盖 23 /* 24 void show(){ 25 //num = 10;//不能在成员方法中赋值 26 } 27 */ 28 } 29 class Demo 30 { 31 public static void main(String[] args) 32 { 33 stu.name = "刘德华";//堆空间的内容是可以改的 34 stu.name = "张学友"; 35 36 // stu = new Student();//其指向的地址不可更改; 37 int x = 10; 38 method(x); 39 System.out.println("x = " + x);
18 多态的概述及其代码
多态的概念:
1.之前我们定义子类,继承自父类。
在使用时:
子类 zl = new 子类();
2.使用多态:可以定义一个"父类类型的引用",指向它的"子类的对象",这种形式就叫:多态
父类 fl = new 子类();
Animal a1 = new Cat();
多态的前提和体现;
1.一定要存在"继承关系";
2.方法重写;
class Animal{ String name; int age; } class Cat extends Animal{ } class Demo { public static void main(String[] args) { //之前的形式 Cat cat = new Cat(); int[] array = {1,2,3,4}; method(array); System.out.println(array[0]); } public static void method(final int a){ // a = 100;//编译错误:值不能被修改; } public static void method(final int[] arr){ arr[0] = 1000;//OK的。堆空间的内容是可以被修改的。 arr = new int[3];//编译错误:地址不能被修改; } } //多态的形式 Animal a1 = new Cat(); a1.name = "波斯猫"; a1.age = 2; System.out.println(a1.name + "," + a1.age + "岁"); } }
19 多态中的成员访问特点
成员变量的访问特点:
1.成员变量:编译看左边(父类中一定要有,否则编译错误);运行看左边(如果子类覆盖父类的成员变量,打印的是父类的)
2.成员方法:编译看左边(父类中一定要有,否则编译错误);运行时看右边(如果子类重写父类的成员方法,调用的是子类的)
3.静态方法:编译看左边(父类中一定要有,否则编译错误);运行时看左边(如果子类重写父类中的静态方法,调用的是父类的)
总而言之:
1.当多态时,访问的成员(成员变量、成员方法)父类中必须要有,否则编译错误。
运行时,只有"被覆盖的普通成员方法"访问的是"子类的",其它都是"父类"的。
1 class Person{ 2 String name; 3 int num = 10; 4 void show(){ 5 System.out.println("Person-->show()"); 6 } 7 static void method(){ 8 System.out.println("Person --> method()"); 9 } 10 } 11 class Student extends Person{ 12 String stuNo;//学员编号 13 int num = 20; 14 void fun(){ 15 System.out.println("Student --> fun()"); 16 } 17 18 19 // p1.stuNo = "it001";//编译错误。编译看左边。如果父类中没有,编译错误 20 System.out.println(p1.name); 21 System.out.println(p1.num);//运行看左边。打印的仍然是父类的 22 23 p1.show();//OK的,父类中有show()。运行时,调用的是子类的。 24 // p1.fun();//不可以。编译看左边-->父类中如果没有,则编译错误; 25 26 p1.method();//打印是父类的。由于method是静态方法。静态方法是属于"类"的。所以它还是看具体的"类型" 27 } 28 } 29 //子类重写父类的show() 30 void show(){ 31 System.out.println("Student --> show()"); 32 } 33 //重写父类中的静态方法 34 static void method(){ 35 System.out.println("Student --> method()"); 36 } 37 } 38 class Demo { 39 public static void main(String[] args) 40 { 41 //以前的形式 42 Student stu = new Student(); 43 stu.name = "张三"; 44 //多态的形式 45 Person p1 = new Student(); 46 p1.name = "李四";
20 多态的好处和弊端
1 多态的好处class Animal{ 2 String name; 3 int age; 4 char sex; 5 } 6 class Cat extends Animal{} 7 8 class Dog extends Animal{ 9 } 10 class Demo { 11 public static void main(String[] args) { 12 //使用多态 13 Cat a1 = new Cat();//a1 = 0x2233 14 Dog a2 = new Dog();//a2 = 0x4455 15 a1.name = "波斯猫"; 16 a1.age = 3; 17 a1.sex = ‘雄‘; 18 // System.out.println(a1.name + "," + a1.age + "岁," + a1.sex); 19 // printCat(a1); 20 printAnimal(a1);//printAnimal(0x2233) 21 a2.name = "阿拉斯加"; 22 a2.age = 3; 23 a2.sex = ‘雌‘; 24 //System.out.println(a2.name + "," + a2.age + "岁," + a2.sex); // printDog(a2); 25 printAnimal(a2);//printAnimal(0x4455) 26 } 27 //定义一个方法,可以打印猫的信息 28 // public static void printCat(Cat c){ 29 //利用"多态"的特性。一个方法的形参可以声明为某个"父类"类型。就表示:可以接收任何的它的子类对象的引用。 30 public static void printAnimal(Animal a){//Animal a = 0x2233(new Cat())//Animal a = 0x4455(new Dog()); 31 System.out.println(a.name + "," + a.age + "岁," + a.sex); 32 }}
1 多态的弊端:1.当多态时,不能访问子类特有成员; 2 class A{ 3 int n = 10; 4 } 5 class B extends A{ 6 int m = 20; 7 } 8 main(){ 9 A a = new B(); 10 System.out.println(a.m);//编译错误。 11 } 12 2.可以通过转型,去访问子类特有成员;
多态中向上转型和向下转
多态中的类型转换:
1.向上转型(隐式的,自动的):"父类"类型的变量,存储"子类对象"的引用;
Animal a = new Cat();//向上转型;
2.向下转型(显示的,强制转换):如果我们确定一个"父类"类型的变量,存储了某个具体的"子类对象"的引用。
我们可以将这个"父类类型"强制转换为它所存储的"子类类型"; Animal a = new Cat();//向上转换
Cat c = (Cat)a;//向下转换
Dog d = (Dog)a;//错误。
3.向下转型由于要使用"强制转换",这就有了隐藏的危险。如果类型不匹配,将在运行时异常:ClassCastException。
Java为我们提供了一种方式,在强制转换前,可以先进行判断,如果为true,再进行转换。
使用关键字:instanceof
它是双目运算符:左操作数 instanceof 右操作数
左操作数:一般是一个"变量名";
右操作数:是某个"类名"
整体的意思:"左操作数"是否是"右操作数"的类型:是:返回true,否则:返回:false
Animal a = new Cat();
if(a instanceof Cat){
Cat c = (Cat)a;//转换是安全的;
}
if(a instanceof Dog){
Dog d = (Dog)a;
}
1 class Animal{ 2 } 3 class Cat extends Animal{ 4 int m = 10; 5 } 6 class Dog extends Animal{ 7 } 8 class Demo { 9 public static void main(String[] args) { 10 Animal a = new Cat(); 11 // System.out.println(a.m);//编译错误。不能访问子类特有成员。 12 Cat c = (Cat)a;//OK的 13 // Dog d = (Dog)a;//运行时异常:ClassCastException: 14 //使用instanceof关键字 15 if(a instanceof Cat){ 16 System.out.println("经判断,是Cat类型"); 17 Cat c1 = (Cat)a;//转换是安全的; 18 } 19 if(a instanceof Dog){ 20 System.out.println("经判断,是Dog类型"); 21 Dog d = (Dog)a; 22 } 23 }