多态、内部类、工厂模式

面向对象的三大特征: 封装 --> 成员变量安全 --> private --> 对应的getter/setter
继承 --> extends --> 提供继承信息的是父类 得到信息的是子类
子类继承父类 --> 子类会继承父类的构造方法吗?
绝对不会继承父类的构造方法 ,子类必须提供自己的构造方法
子类在创建对象的时候,会调用父类的构造方法?
会调用父类的构造方法 ,默认会调用无参构造方法
若父类没有提供无参构造方法,子类就需要显式调用父类的有参构造方法
class A {
private int a;
若一个类中没有提供任何构造方法? 可以创建对象,默认提供一个无参构造方法
若一个类提供了一个构造方法 ,默认提供的无参构造方法还存在吗? 不在
public A(int a){
this.a = a;
}
}
class B extends A{
子类可以继承父类中的私有属性吗? --> 不能继承
ps个人:可以继承的,java是公有继承,所有都能继承
private-->访问权限修饰符
父类中私有的属性或方法只是对子类设置了访问权限无法访问


public B(){
super(10);
}
public static void main(String[] args){

子类创建对象的过程?
先创建父类对象,然后在创建子类对象
ps:先调用父类的构造方法,然后在创建子类对象
B b = new B();
}
}
多态
什么是多态呢?
同一个事物被不同对象所触发,得到的结果不同就是多态

你和你姐生出来,然后你和你的姐姐都可以成长,但是同样的成长,你长的丑,你姐就很漂亮,现实的多态就必须是亲子女关系

触发对象多态的一个必要前提必须是继承关系

需求:
设计一个员工类,其中有计算员工的薪水方法,根据员工职务的不同,薪水的计算方式也不同
员工类型 薪水构成
----------------------------------------
经理(manager) 底薪(salary)+奖金
销售人员 (salesman) 底薪+提成
普通员工(staff) 底薪+补贴
分析: 3个类 -->
底薪 , 计算薪水(方法体?-->抽象方法) --> 父类员工类(employee)

设计一个测试类:
场景:年终,领导找员工谈话,让员工介绍自己的薪水 --> 写方法
看polymorphic案例

多态的形式:
1.对象多态前提:
需要是继承关系也可以是实现关系
父类 --> 抽象类(特殊的父类,可以提供抽象方法) --> 接口(特殊的抽象父类,没有构造方法,方法可以定义抽象方法)
2.方法多态
重载:方法名相同,参数列表不同(个数,顺序,数据类型)
3.对象多态:
父类的引用可以获取一个子类的对象
ps:引用<-->对象

多态的作用:
当把不同的子类对象当做父类类型来看待,可以屏蔽不同子类对象之间的实现差异,从而达到代码的通用性


里氏(代)转换原则
1.对象的向上转型
子类对象赋值给父类类型的引用时,会自动将子类对象的类型提升为父类类型
语法:
父类类型 对象名 = new 子类类型();
此时,该对象只能调用父类所有的可见属性和方法,不能调用子类特有的属性和方法

2.对象的向下转型
将提升后父类对象强制转换为原有的子类类型
语法:
子类类型 对象名 =(子类类型)父类对象
此时,该对象即可以调用父类中的属性和行为,也可以调用子类特有的属性和行为


instanceof关键字 帮助我们检查要转换的对象是不是原有类型 -->场景:多态的向下转型
首先这个关键字会的到一个返回值--> boolean
若结果是true 当前对象就是对应类型
若结果是false 当前对象不是对应类型
语法:
对象 instanceof 类型

看polymorphic2案例

多态中成员属性和成员方法的访问
看polymorphic3案例

设计模式(DesignMode):
软件前辈通过不断的总结,得到一种方式减少代码量,提高复用性
推荐一本书:大话设计模式
java一共有23种设计模式
创建型设计模式(5个):工厂模式,单利模式 ....
结构型设计模式(7个):装饰者模式(IO流)...
行为型设计模式(11个):模板模式...

ps:设计模式的堆叠,其实组合起来就是框架
SSH SSM --> JavaEE的框架


模板设计模式(Template)
在父类中定一个方法的总体骨架,而将某些实现步骤拿到子类中来完成,不同子类可有不同的完成效果
需求:测试某段代码耗时

单利设计模式(Singleton)
在开发中保证创建对象始终是唯一的
懒汉模式
1.创建一个本类类型的静态私有属性
2.构造方法私有化
3.设计一个静态方法返回值是本类类型
有一个判断逻辑 当前私有属性是否为null
若是null就创建对象,然后返回
若不是null,就直接返回
ps: 在多线程并发访问的前提下,懒汉模式是线程不安全的(可以创建出新的对象)

饿汉模式
1.创建一个本类类型的静态私有属性并赋值
2.构造方法私有化
3.设计一个静态方法返回当前对象

简化版本
class Single{
1.构造方法私有化
private Single(){
}
2.
public static final Single instance = new Single();
}

工厂设计模式(Factory)
考虑一个简单的软件应用场景,一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等),
这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,
如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,
并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。


女娲造人
女娲工厂
思想 特征,行为

简单工厂(SimpleFactory)
工厂可以帮助我们管理对象的创建
若是有新的对象加入,修改原码(工厂的原码)
工厂模式一般都是应用于底层框架,无法修改原有代码的

抽象工厂(AbstractFactory)
创建对象时有接口中所提供的方法,谁要实现就就能创建对象
随着新对象的加入,虽然不需要修改原码了,但是累文件会逐渐的争夺

总结:
工厂对我们的作用就是管理对象的创建,减少管理成本
创建对象只能通过工厂模式这种形式创建从而减少了,代码的记忆量
因为无论是简单还是抽象都有自己的弊端,根据实际需求酌情选择

ps:
单利是为了保证对象唯一,简单工厂又不能修改原码,其实在一个概念面前都是无用的 --->反射


内部类(InnerClass)
书写在类的内部的类,内部类
内部类根据不同的修饰符或定义的位置不同:
如下四类:
成员(实例)内部类 : 内部类没有使用static修饰
静态内部类: 内部类使用列static修饰
局部内部类: 定义在方法体中的类
匿名内部类: 这个类没有自己的名字,适用于只只使用一次,属于局部内部类的特殊版本
ps:对于每一个内部类来说java都会编译一个独立的.class文件
成员内部类 : 外部类类型$成员内部类的类名.class
静态内部类 : 外部类类名$静态内部类的类名.class
局部内部类 : 外部类类名$数字内部类名字.class
匿名内部类 : 外部类类名$数字.class

成员内部类(MemberInnerClass)
说明:
外部类的访问权限修饰符:public,默认的
内部类可以看做是外部不类的一个成员,那么内部类可以使用public/private/protected/默认修饰
因为是成员内部类所有坚决不能使用static 修饰
成员内部类是属于外部类对象,不属于外部类
特点:
1.创建成员内部类对象前,必须有外部类对象,通过外部类对象创建成员内部类对象
(存在成员内部类对象的时候,一定存在外部类对象)
语法:
外部类类名.内部类类名 对象名 = 外部类对象.new 内部类类型();
2.成员内部类自动持有外部类对象的引用,内部类可以直接访问外部类的成员和方法
3.外部类中不能直接访问内部类的成员,必须通过内部类的实例来访问
4.成员内部类不能定义静态成员和的静态方法,只能定义成员属性和成员方法
5.若成员内部类和外部类存在同名属性如何访问
外部类类名.this.外部类属性的

静态内部类(StaticInnerClass)
内部类使用static修饰的类,外部类绝对不能使用static 修饰
特点:
1.静态内部类的实例不会自动持有外部类的引用,在创建内部类的实例,不必创建外部类对象了
语法:
外部类类名.内部类类名 对象名 = new 外部类类名.内部类类名();
2.静态内部类可以直接访问外部类的额静态成员,如果访问外部类的实例成员,必须通过外部类的实例来访问
3.在静态内部类中可以定义静态属性和方法也可以定义成员属性和方法
4.可以通过完成的类名直接访问静态内部类中的静态成员

总结:成员内部类就看做是类的一个成员属性(是属于对象)
静态内部类就看做是类的一个静态属性(属于类的)


局部内部类(LocalInnerClass)
局部内部类是一个打死都不用一个类
在方法体中定义的内部类,其课件范围就是当方法体,和方法体中的局部变量是同一个级别
特点:
1.不能使用任何权限修饰符,可以有一个默认的
2.局部内部类只能在当前方法中使用
3.局部内部类和成员内部类一样,不能包含静态成员
4.局部内部类和成员内部类一样,可以访问外部类的成员
5.局部内部类访问方法中的局部变量时,这个变量需要是final修饰的,在java7之后自动添加final

为什么局部内部类访问的局部变量需要使用final修饰?
当方法调用完成的时候,方法会弹栈操作,方法中所有的局部变量都会被销毁
然后在方法中存在局部内部类,局部内部类的空间是在堆中,堆空间对栈中的局部变量会有引用,虽然栈中的空间销毁
堆还没有,出现内存泄漏的问题,就需要将局部内部类所访问的局部变量改变空间,存到常量池中,就算栈这种空间回收了
,常量池中的引用还在,就不会出现内存泄漏

匿名内部类(AnonymousInnerClass)
匿名内部类没有自己的名字,其实只适合使用一次
在开发中实现某个接口,需要定义类的方式来完成,但是这个类只使用一次,这时就可以使用匿名内部类
ps:匿名内部类是--> Lambda表达式的前身
面向对象编程 Lambda表达式的出现java支持了面向函数式编程的转换 --> scala语言就是类似于Lambda表达式
特点:
1.匿名内部类本身没有构造方法,但是会调用父类构造方法
2.匿名内部类可以提供一段初始化代码块
3.匿名内部类主要的作用是来处理接口使用


public interface IAirTransportation {
    // 空运
         void sendAir();
}

public interface ILandTransportation {
    //陆运
    void sendLand();
}
/**
 * 
 */
package com.qfedu.Day12.HomeWork;

public abstract class Company  {
        private String name;
        

        public Company() {
            
        }
        

        public Company(String name) {
            
            this.name = name;
        }


        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
        
}
/**
 * 
 */
package com.qfedu.Day12.HomeWork;

public class SFCompany extends Company implements ILandTransportation,IAirTransportation{
    
    public SFCompany() {
        super();
        // TODO Auto-generated constructor stub
    }

    public SFCompany(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    /* (non-Javadoc)
     * @see com.qfedu.Day12.HomeWork.IAirTransportation#sendAir()
     */
    @Override
    public void sendAir() {
        System.out.println("顺丰快递发空运");
        
    }

    /* (non-Javadoc)
     * @see com.qfedu.Day12.HomeWork.ILandTransportation#sendLand()
     */
    @Override
    public void sendLand() {
        System.out.println("顺丰快递发陆运");
        
    }

}
/**
 * 
 */
package com.qfedu.Day12.HomeWork;

public class STCompany extends Company implements IAirTransportation{

    
    public STCompany() {
        super();
        // TODO Auto-generated constructor stub
    }

    public STCompany(String name) {
        super(name);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void sendAir() {
        System.out.println("申通快递发空运");
        
    }

}

/**
 * 
 */
package com.qfedu.Day12.HomeWork;

public class YDCompany  extends Company implements ILandTransportation{


    public YDCompany() {
        super();
        
    }

    public YDCompany(String name) {
        super(name);
        
    }

    /* (non-Javadoc)
     * @see com.qfedu.Day12.HomeWork.ILandTransportation#sendLand()
     */
    @Override
    public void sendLand() {
        System.out.println("韵达快递发陆运");
        
    }

}
/**
 * 
 */
package com.qfedu.Day12.HomeWork;

public class Person {
      //接口-->是一个特殊的抽象父类
    //多态 --> 继承或实现 接口可以接受一个实现了接口的子类引用(对象)
    //将参数类型改成接口,接受的参数是不是只能是实现了接口的类
    public void sendLand(ILandTransportation l) {
          l.sendLand();
    }
    public void sendAir(IAirTransportation a) {
        a.sendAir();
    }
    /**
 * 
 */
package com.qfedu.Day12.HomeWork;

public class Test {

    public static void main(String[] args) {
    //1.
          Car car = new Car();
          car.drive();
    //2.
          BaoMu bm = new BaoMu();
          bm.maicai();
          bm.zuofan();
          
          //6.
         Person p = new Person();
         STCompany st = new STCompany();
         YDCompany sd = new YDCompany();
         SFCompany sf = new SFCompany();
         //重载的问题,重载可以自动选择最合适的方法
         p.sendLand(sf);
         p.sendAir(sf);
              
    }

}

}
原文地址:https://www.cnblogs.com/lijun199309/p/9471213.html