07-复用类

简介
  复用类顾名思义就是利用已有的代码实现某功能,每个人都不想不断做重复性的工作,复用类就是把之前的代码通过组合或者继承等方法重新利用起来,利用复用类不但可以使代码更加简洁,灵活性也能得到很高的提升。
1,组合语法
    组合就是将基本类型,String类型或者对象引用作为某个类的成员变量,通过引用变量控制其个自功能,例如实现个汽车类,可以把引擎类作为成员变量引用,然后引擎类就可以给汽车类提供引擎功能使用了。
public class Car {
    private String name,version;
    //初始化给变量赋值
    private int size=10;
    private CarEngines engines;
    //构造器给变量赋值
    public Car(String name,String  version,int size,CarEngines engines){
        this.name=name;
        this.version=version;
        this.size=21;
        engines=new CarEngines();
    }
 
    //代码块赋值
    {
        this.name="qq";
        this.version="zx1.0.0";
        this.size=12;
        engines=new CarEngines();
        
    }
    //利用引擎类启动
    public void run(){
        engines.run();
    }
    //利用引擎类关闭
    public void close(){
        engines.close();
    }

    //set方法给变量赋值
    public void setName(String name) {
        this.name = name;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public void setEngines(CarEngines engines) {
        this.engines = engines;
    }
}


/**
 * 汽车引擎
 */
class CarEngines{

    public void run(){
        System.out.println("启动汽车");
    }

    public void close(){
        System.out.println("关闭汽车");
    }
}

    从代码示例中可以看到,给变量赋值有很多种方式,根据示例情况赋值,例如set方法可以在运行中为某个实例赋n次值,而通过构造器只能为某个实例赋一次值。

2,继承语法概念
    java中如果需要A类复用B类提供可以共用的方法,可以通过extends继承B。那么A就拥有了B的部分功能(只能继承B访问权限允许的域和方法)  ,java的所有对象隐式父类都是Object,除非明确指定继承其他类,一个子类只能继承一个父类,不能重复继承。
如果B类构造方法带有参数,那么A类构造器必须使用supper指定要执行的B类构造器,不然会报错.示例如下:
//父类
public class Father {
    private String name="lalalala";
    public int size;
    public String  common="f1";
    public Father(int i){
        System.out.println(i);
    }
    public void print(){
        System.out.println("name:"+name);
    }

    public void printSize(){
        System.out.println("fffff");
    }
}

//子类
public class Child extends Father {
    public String common="c1";
    public Child(){
        super(1);//必须执行,不然会报错,
        /**
         * 参数的时候需要明确执行,无参的时候是程序隐式执行父构造器
         * 也就是说子类构造器构造执行时必须先执行父构造器,不然就会报错
         */
    }
    public void printName(){
        //可以直接调用父类方法
        print();
    }
    @Override
    public void printSize(){
        System.out.println("ccccc");
    }

    public void setSize(){
        this.size=123;//可以直接使用父类允许访问权限的域和方法
        //this.name  那么在父类中设置为private私有的, 所以子类服务继承使用
    }

    /**
     * 父类和子类同时拥有的方法和变量名称时,在通过子类调用时如下:
     * 默认调用则是调用子类的域和方法,默认调用其实也是this调用
     * 指定super调用则是调用父类的域和方法。
     * 通过this调用则是调用子类本身的域和方法。
     */
    @Test
    public void show(){
        System.out.println("defult:"+common+",father:"+super.common+",child:"+this.common);
        printSize();
        super.printSize();
        this.printSize();
        
        //结果:
        //defult:子类.common,father:父类.common,child:子类.common
        //子类:printSize方法
        //子类:printSize方法
        //父类:printSize方法
    }
}

    注意。初始化的时候先初始化父类的静态(按顺序),再初始化子类的静态(按照顺序),再初始化父类的成员变量,构造块,最后再初始化父类的构造器,之后再初始化子类的成员变量,构造块,再初始化子类的构造器。详情请看笔记《02-方法传参和初始化与垃圾回收清除》初始化部分。

3,向上转型
    在java语言中,子类可以认为是父类的一种类型,是is-a的关系。向上转型的概念指的是,把子类当做父类使用,可以使用父类类型引用指向子类实例,调用父与子共有的方法和域,例如,A类继承B类, 有个方法method(A a),而将B传入method方法作为参数java支持,这就是向上转型。如下:  
//方法参数是父类类型
public static void printSizeByFather(Father f){
    f.printSize();//输出结果是子类实例内容,即“子类:printSize方法”
}
public static void main(String[] args) {
    printSizeByFather(new Child());//传入的子类实例
}

    父类引用可以指向子类实例,也可以将父类作为参数子类传入参数,java通过RTTI类判断具体是哪个子类实例还是父类实例。

4,final关键字
    final的概念如下:
    1,一个永远不会被改变的常量
    2,运行时被初始化的值,而不会被改变。
    编译期常量在java中必须是基本数据类型,String应该也可以。并且以final关键字修饰,在定义时必须赋值。这就是编译期常量,比编译期常量的好处是在编译期时候就将“编译器常量”赋值分配空间。减轻一些运行期的负担,一个既是static又是final的变量域只占据一块不能改变的储存空间。如果想看编译期和运行期区别就看之前的笔记《java中编译器和运行期的区别》。
4.1 空白final常量
    从final概念就知道final是修饰的变量值一旦赋值后就不能修改,引用是不能修改指定的位置,对象本身可以修改,只是针对引用角度来说不能被修改。那么如果final一开始没有赋值,怎么处理?正常情况下如果存在有final修饰的变量且没有赋值编译器会报错。
以下示例:
/**
 * TODO 测试final空白变量(什么final并没实现赋值)什么时候可以赋值。
 * 结果在普通方法中无法赋值,而再构造器方法中可以赋值
 */
private final Hello hello;
private final Hello hello2=new Hello();

//普通方法
public void isMethodCreateFinal(){
    //hello=new Hello(); 编译不通过。无法赋值
}

//构造器方法
public Handler(){
    hello=new Hello();//可以赋值
    //hello2=new Hello(); 构造器只能对未赋值的final变量赋值,但不能改值,编译器报错
}

  final的空白变量可以用构造器赋值。但是已经赋值的final常量则不能再更改了,而其他方法时不能给构造器赋值,原因是因为构造器只会执行一次,也符合final变量不能改变的原则。

final实现不可变对象,示例:
//可变对象
public class Handler {
    private int n;
    public Handler(int n){
        this.n=n;
    }
    public void show(){
        if (n!=n){
            System.out.println("线程不安全");
        }
    }
}
//不可变对象
class HandlerFinal{
    private final int n;
    public HandlerFinal(int n){
        this.n=n;
    }
    public void show(){
        System.out.println("线程安全");
    }
}

  对象可变与否,是看对象的状态即变量是不是可以共享以及可以被修改,示例中Handler类和Handler类只有一个基本类型的n变量,而且更改n变量只能通过构造方法才可以,但由final修饰的n才是不可变对象,对象实例化操作不是原子性的,上面有替代new对象时,会分为好几个步骤,比如先初始化静态变量以及父类变量等等,最后才实例化对象。试想下,但java对final修饰的变量做了特殊处理,导致final修饰的变量可以实现其不可变性,即线程安全。

4.2 final参数
    示例如下:
/**
     * TODO final 方法参数
     * @param i
     */
    public void finalParam(final Integer i){
        System.out.println(i);
        //i=new Integer(3);可以读但无法修改final参数,否则编译器不通过,常用于匿名内部类
    }
    @Test
    public void finalParamRun(){
        /**
         * 可以正常传不同值
         */
        finalParam(new Integer(3));
        finalParam(new Integer(5));
    }

此时的方法参数map由final修饰,就是final方法。final方法参数能够传不同的值,但不能修改参数,否则报错

4.3 final方法
    设计final修饰方法有两个原因:1,final修饰的方法不能被覆盖,为了避免父类方法被覆盖导致方法逻辑破坏,但需要可以继承,可以通过final禁止被覆盖。原因2已经失效,但可以提下,在之前的final方法是jvm优化的一种方式,final修饰的方法能够提高性能。但java已经逐渐的抛弃了这种优化方案,所以原因2已经不再重要。而现在如果使用final修饰方法的话,主要原因是防止方法该方法被覆盖。
示例:
class FinalMethod{
    public final void finalMethod(){
        System.out.println();
    }
    public void method(){
        System.out.println();
    }
}
 尝试覆盖方法
 
 

  final和private的区别?

    区别1:final修饰的方法不能被覆盖,但是能够继承。子类依然可以调用父类的final方法,但是无法覆盖。而private修饰的方法无法继承,更别提覆盖了。
    区别2:final至少一种修饰,还可以对这个方法设定其他的访问权限,如public,default,protected,private等。
   另外,private是隐式的final修饰。所以如果再给private 方法添加final修饰,是可以但没有实际意义
    不能被覆盖仅仅是final方法,final变量就没有覆盖的概念 了。是可以在子类写重名的成员变量。
4.4 final类
   如果不希望自己创建的类有子类即不希望被继承,那么就可以使用final修饰类。 final修饰的类在复用中的作用主要是不能被继承,另外final的类的所有方法都是隐式的final修饰。
格式:
final class FinalClass{ }

尝试继承结果:

5,总结:
向上转型作为是否使用继承和组合的重要因素,利用向上转型可以让代码更加灵活,耦合度更低,在程序中尽量少使用继承,多用组合,面向接口开发把具体实现封装,想要理解的话可以看设计模式:策略模式。

 

 
 
 
 

转载于:https://www.cnblogs.com/likejiu/p/10023178.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值