一、多态:同种事物不同的表现形式
实现多态的三个前提:1.要实现子父类继承关系(通过类实现一个接口),2.要有方法的重写,3.父类引用指向子类对象
package com.bianyiit.cast;
public class Demo1 {
//多态:实现的三个前提
//1.要实现子父类继承关系(通过类实现一个接口)
//2.要有方法的重写
//3.父类引用指向子类对象
public static void main(String[] args) {
//new Animal().eat();
Animal a1 = new Dog(); //new Dog-->子类对象 Animal a1-->父类引用
a1.eat();
}
}
//定义一个动物类
class Animal{
//成员方法
public void eat(){
System.out.println("吃东西..");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃泥..");
}
}
二、多态中成员的特点(变量、方法和静态方法)
1.动态绑定:在运行的时候会指向具体的对象
2.编译期(没点击运行之前,如果出现红线表明编译时出错)和运行期(点击运行时,正常运行还是报错)
package com.bianyiit.cast;
public class Demo2 {
public static void main(String[] args) {
//System.out.println(new Dog2().color);
Animal2 a1 = new Dog2();
System.out.println(a1.color);
a1.eat();
a1.sleep();
}
}
class Animal2{
//定义一个成员变量
String color="白色";
public void eat(){
System.out.println("我是一只动物..");
}
public static void sleep(){
System.out.println("动物正在睡觉..");
}
}
class Dog2 extends Animal2{
String color="黑色";
@Override
public void eat() {
System.out.println("狗啃泥..");
}
//@Override
public static void sleep() {
System.out.println("狗正在睡觉..");
}
}
1.成员变量:编译期,如果父类里面没有成员变量就会报错,如果子类里面没有成员变量没问题
运行期,运行出来的结果显示的是父类的成员变量的值
2.成员方法:编译期,如果父类里面没有成员方法就会报错,如果子类里面没有成员方法没问题
运行期,运行出来的结果显示的是子类的成员方法的内容
3.静态方法:编译期,如果父类里面没有静态方法就会报错,如果子类里面没有静态方法没问题
运行期,运行出来的结果显示的是父类的静态方法的内容
总结:使用多态应用的时候,成员变量 成员方法 静态方法编译期看的都是父类(父类中有这个东西才能够使用)
* 运行时只有成员方法看的是子类的具体对象(调用的是子类的方法----动态绑定)
* 注意:多态有一个局限性:无法调用子类特有的成员
三、如果想去调用子类特有的成员该怎么办?
调用子类特有的成员:
数据类型的转换:
基本数据类型的转换
自动转换 (由小转大)
byte shor char-->int-->long-->float-->double boolean不参与任何数据的转换
强制转换(由大转小---会损失精度)
引用数据类型的转换:
向上转型(小的转大的)
向下转型(大的转小的)
package com.bianyiit.cast;
public class Demo3 {
public static void main(String[] args) {
Animal3 a1 = new Dog3();//(向上转型---小的自动转大的) 狗自动转换成动物
a1.eat();//动态绑定---调用的是子类的方法
Dog3 d1=(Dog3)a1; //向下转型(大的转小的) 动物强制转换成狗
d1.eat();
d1.sleep();//转型之后调用(子类)狗里面的特有的成员方法
}
}
class Animal3{
public void eat(){
System.out.println("动物");
}
}
class Dog3 extends Animal3{
@Override
public void eat() {
System.out.println("狗");
}
public void sleep(){
System.out.println("狗正在睡觉..");
}
}
四、多态的优点
package com.bianyiit.cast;
public class Demo4 {
public static void main(String[] args) {
/* 多态的优点:1.继承的优点也就是多态的优点(1.提高了代码的复用性 ) 2.提高程序的扩展性。*/
//以工厂生产手机为例
Factory f1 = new Factory();
f1.produce(new XiaoMiPhone());
f1.produce(new RedNotePhone());
}
}
//定义一个工厂用来生产手机
class Factory{
public void produce(Phone p){
p.run();
}
}
class Phone{
public void run(){
}
}
class XiaoMiPhone extends Phone{
@Override
public void run() {
System.out.println("生产小米手机中..");
}
}
class RedNotePhone extends Phone{
@Override
public void run() {
System.out.println("生产红米手机中..");
}
}
五、内部类的使用
5.1 成员内部类
package com.bianyiit.cast;
public class Demo7_ChengYuanNeiBuNei {
public static void main(String[] args) {
//创建外部类对象 直接通过外部类的对象调用外部类的成员方法(内部包含内部类的实例化成员)
//new Out().run();
new Out().new In().study(); //成员方法
System.out.println(new Out().new In().num); //成员变量
}
}
//定义一个外部类
class Out{
//成员变量
int num=10;
//成员方法
/*public void run(){
System.out.println("--调用外部类的成员方法-->然后在该方法中调用内部类的成员");
//创建内部类的第一种方式,在外部类的成员方法中创建内部类对象
//new In().study();
//System.out.println(new In().num);
}*/
//成员内部类(与成员变量处于同一级别)
class In{
//内部类的成员变量
int num=20;
//内部类的成员方法
public void study(){
System.out.println("学习中..");
}
}
}
5.2 静态内部类
package com.bianyiit.cast;
public class Demo8_JinTaiNeiBuNei {
//静态内部类 静态内部类里面不能访问非静态成员
public static void main(String[] args) {
new Animal8.Dog8().sleep();
System.out.println(new Animal8.Dog8().num);
}
}
class Animal8{
static int num=10;
static class Dog8{
int num=20;
public void sleep(){
System.out.println("狗正在睡觉..");
}
}
}
5.3 局部内部类
package com.bianyiit.cast;
public class Demo9_JuBuNeiBuNei {
public static void main(String[] args) {
//因为局部内部类的作用范围只在外部类的成员方法里面,一旦出了这个范围就不能使用了
//所以局部内部类的创建只能在外部类的成员方法里面去创建,并且只能在局部内部类的后面才能创建成功!
new Out9().printout();
}
}
class Out9{
//成员变量
int num=10;
//成员方法
public void printout(){
System.out.println("这是一个外部类的方法");
//局部变量
int num=20;
//如果在这里创建局部内部类对象,在此之前连类都没有定义出来,所以在编译时就报错了!!
//new In9().printin();
//局部内部类
class In9{
//局部内部类的成员变量
int num=30;
//局部内部类的成员方法
public void printin(){
System.out.println("这是一个局部内部类");
}
}
//如果在这里创建局部内部类对象并调用方法,可以使用!
new In9().printin();
System.out.println(new In9().num);
}
}
5.4 匿名内部类(这个在多线程中用的很多)
package com.bianyiit.cast;
public class Demo10_NiMingNeiBuNei {
public static void main(String[] args) {
//匿名内部类:用来创建类/接口的子类对象用的
Out10 o1= new Out10(){
@Override
public void Out10() {
System.out.println("我是一只猫");
}
};
o1.Out10();
//匿名对象+匿名内部类
new Out10(){
@Override
public void Out10() {
System.out.println("我是一头有思想的牛");
}
}.Out10();
//多态:父类引用指向子类对象,动态绑定,在运行的时候会指向子类对象,它的会自动调用子类重写的成员方法
//这里输出的效果和使用匿名内部类的效果是一致的!
Out10 o2=new In10();
o2.Out10();
/*为什么要使用匿名内部类,减少代码量
匿名内部类和通过继承父类创建一个子类,然后调用子类重写的成员方法的效果是一致的*/
}
}
class Out10{
public void Out10(){
System.out.println("我是一只动物!!");
}
}
//这里通过new Out10().out10();来使用子类的方法
class In10 extends Out10{
@Override
public void Out10() {
System.out.println("我是一只哈巴狗!");
}
}
六、权限修饰符的比较
package com.bianyiit.quanxian.public1;
public class Demo {
public static void main(String[] args) {
printPublic();
printDefault();
printPrivate();
printProtected();
}
public static void printPublic(){
System.out.println("public方法");
}
static void printDefault(){
System.out.println("default方法");
}
private static void printPrivate(){
System.out.println("private方法");
}
protected static void printProtected(){
System.out.println("protected方法");
}
}
package com.bianyiit.quanxian.public1;
public class Demo1 extends Demo{
public static void main(String[] args) {
Demo.printPublic();
Demo.printDefault();
Demo.printProtected();
}
}
package com.bianyiit.quanxian.protect;
import com.bianyiit.quanxian.public1.Demo;
public class Demo2 extends Demo{
//在不同的包中,只有继承父类之后才能使用protected修饰的方法,而不能使用default修饰的方法,这是protected和default最大的区别
public static void main(String[] args) {
Demo.printPublic();
Demo.printProtected();
}
}
七、多态总结
1.多态:父类的引用指向了子类对象
Animal a=new Cat();
2.1 多态的优点
1.继承的优点也就是多态的优点
2.提高程序的扩展性。
2.2 缺点:无法直接访问子类特有的成员。
多态就是向上转型。
如果想访问子类特有的成员?向下转型
3 继承:优缺点
3.1 优点:
1.提高代码的复用性
2.提高程序的可维护性
3.2 缺点:类与类之间的关联更加的密切。(耦合性增强)
4 如何解决高耦合? 使用接口
4.1 封装的优点:
1.提高代码的复用性
2.提高代码的安全性。
课后作业
package com.bianyiit.zonghe;
public class Demo_Phone {
public static void main(String[] args) {
Factory factory = new Factory();
factory.prodece(new XiaoMiPhone());
factory.prodece(new RedNotePhone());
factory.prodece(new PupperNotePhone());
/*factory.run(new XiaoMiPhone());
factory.run(new RedNotePhone());
factory.run(new PupperNotePhone());*/
}
}
//工厂:生产手机
class Factory{
/*public void run(XiaoMiPhone x){
x.produceXiao();
}
public void run(RedNotePhone r){
r.produceRed();
}
public void run(PupperNotePhone p){
p.producePupper();
}*/
public void prodece(Phone p){
p.run();
}
//Phone p=new XiaoMiPhone();
//p.run();当使用多态创建对象时,当父类和子类使用的是同一个成员方法,那么对象调用的是子类的成员方法
}
abstract class Phone{
public abstract void run();
}
//小米手机的生产方法
class XiaoMiPhone extends Phone{
@Override
public void run() {
System.out.println("正在生产小米手机...");
}
}
//红米手机的生产方法
class RedNotePhone extends Phone{
@Override
public void run() {
System.out.println("正在生产红米手机...");
}
}
//紫米手机的生产方法
class PupperNotePhone extends Phone{
@Override
public void run() {
System.out.println("正在生产紫米手机...");
}
}