java复用类

组合和继承

组合:在新类中产生现有类对象;
继承:按照现有类的类型来创建新类。

使用组合和继承的实例:

class Plate{
    public Plate(int i) {
        System.out.println("Plate constructor");
    }
}
class DinnerPlate extends Plate{
    DinnerPlate(int i){
        super(i);
        System.out.println("DinnerPlate constructor");
    }
}
class Utensil{
    Utensil(int i){
        System.out.println("Utensil constructor");
    }
}
class Spoon extends Utensil{
    Spoon(int i ) {
        super(i);
        System.out.println("Spoon constructor");
    }
}
class Fork extends Utensil{
    Fork(int i){
        super(i);
        System.out.println("Fork constructor");
    }
}
class Knife extends Utensil{
    Knife(int i){
        super(i);
        System.out.println("Knife constructor");
    }
}
class Custom{
    Custom(int i){
        System.out.println("Custom constructor");
    }
}
public class PlaceSetting extends Custom{
    private Spoon spoon;
    private Fork fork;
    private Knife knife;
    private DinnerPlate dinnerPlate;

    public PlaceSetting(int i) {
        super(i+1);
        spoon = new Spoon(i+2);
        fork = new Fork(i+3);
        knife = new Knife(i+4);
        dinnerPlate = new DinnerPlate(i+5);
        System.out.println("PlaceSetting constructor");
    }
    public static void main(String[] args) {
        PlaceSetting ps = new PlaceSetting(4);
    }
}

Custom constructor
Utensil constructor
Spoon constructor
Utensil constructor
Fork constructor
Utensil constructor
Knife constructor
Plate constructor
DinnerPlate constructor
PlaceSetting constructor

组合和继承都允许在新的类中放置子对象,组合是显示地做,而继承是隐式地做。组合技术通常用于想在新类中使用现有类的功能而并非它的接口。

代理

将一个成员对象置于所要构造的类中(就像组合),但与此同时在新类中暴露了该成员对象的所有方法(就像继承)。例如,太空船需要一个控制模块:

class SpaceControls{
    void up(int velocity){}
    void down(int velocity){}
    void left(int velocity){}
    void right(int velocity){}
    void forward(int velocity){}
    void back(int velocity){}
    void turnBoost(){}
}

构造太空船的一种方式是使用继承:

class SpaceShip extends SpaceControls{
    private String name;
    public SpaceShip(String name) {
        this.name = name;
    }
    public String tosString() {
        return name;
    }
    public static void main(String[] args) {
        SpaceShip ship = new SpaceShip("NESA Protextor!");
    }
}

但是,SpaceShip并非真正的SpaceShipControls类型,使用代理的方式实现:

public class SpacshipDelegation {
    private String name;
    private SpaceShipControls controls = new SpaceShipControls();
    public SpacshipDelegation(String name){
        this.name = name;
    }
    public void down(int velocity) {
        controls.down(velocity);
    }
    public void back(int velocity) {
        controls.back(velocity);
    }
    public void left(int velocity) {
        controls.left(velocity);
    }
    public void right(int velocity) {
        controls.right(velocity);
    }
    public void up(int velocity) {
        controls.up(velocity);
    }
    public void forward(int velocity) {
        controls.forward(velocity);
    }

    public static void main(String[] args) {
        SpacshipDelegation delegation = new SpacshipDelegation("NESA Protector");
        delegation.forward(100);
    }

}

fianl关键字

三种情况:数据、方法和类

final数据

1 、一个永不改变的编译是变量。
2、一个在运行时被初始化的值,该值不希望被改变。

在java中,这类变量必须是基本数据类型,并且是以关键字final表示,定义的时候必须对其进行赋值。
一个既是static又是final的域只很真哪句一段不能改变的存储空间。
对于基本类型,final使数值恒定不变;而对于对象引用,final使易用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象,然而对象自身却是可以修改的。
示例:

package com.wkx.seven.finall;

import java.io.File;
import java.util.Random;
public class FinalData {
    private static Random random = new Random(47);
    private String id;

    public FinalData(String id) { this.id = id ; } 

    private final int valueOne = 9;
    private static final int VALUE_TWO = 99;

    public static final int VALUE_THREE = 39;

    private final int i4 = random.nextInt(20);
    static final int INT_5 = random.nextInt(20);

    private Value v1 = new Value(11);
    private final Value v2 = new Value(22);
    private static final Value VAL_3 = new Value(33);

    private final int[] a = {1,2,3,4,5,6};
    @Override
    public String toString() {
        return id + ": " + "i4 = " + i4 + ",INT_5 = " + INT_5;
    }

    public static void main(String[] args) {
        FinalData fd1 = new FinalData("fd1");
//      fd1.valueOne ++;     //valueOne为final类型的,值不可改变
        fd1.v2.i++;          //v2引用不可变,但指向的对象可以改变
        fd1.v1 = new Value(9);
        for (int i = 0; i < fd1.a.length; i++) {
            fd1.a[i]++;      //a的指向不可改变,但数据内容可以改变
        }
//      fd1.v2 = new Value(10);    //v2对象的引用不可以改变
//      fd1.VAL_3 = new Value(10);  //对象的引用不可以改变
//      fd1.a = new int[3];        //引用为final类型的,不可改变
        System.out.println(fd1);
        System.out.println("creating new finaldata");
        FinalData fd2 = new FinalData("fd2");
        System.out.println(fd1);
        System.out.println(fd2);
    }
}
class Value {
    int i;
    public Value(int i ){this.i = i ; }
}

执行结果:
fd1: i4 = 15,INT_5 = 18
creating new finaldata
fd1: i4 = 15,INT_5 = 18
fd2: i4 = 13,INT_5 = 18

不能因为某数据是final的就认为在编译时可以知道它的值,在运行时使用随机生成的数值来初始化i4和INT_5可以说明这一点,在fd1和fd2中,INT_5的值是不可以通过创建第二个对象加以改变的,是因为它是static的,在装载时已被初始化,而不是每次创建新对象时都初始化。
另外值得注意的是,不能因为v2是final的,就认为无法改变它的值,由于它是一个引用,final意味着无法将v2再次指向另一个新的对象,对数组具有相同的意义,数组只不过是另一种引用。

1、空白final:被声明为final但又未给定初值的域,无论什么情况,要确保空白final在使用前必须初始化,这样空白final可以做到根据对象而有所不同,我们只需要在不同的构造器中对空白final进行不同的赋值即可。
2、final参数:java允许在参数列表中以声明的方式将参数指明为final,意味着无法在方法中更改参数引用所指向的对象:

package com.wkx.seven.finall;
public class FinalArgements {
    void with (final Gizmo g){
    //  g= new Gizmo();  错误,无法改变final引用的指向
    }
    void without(Gizmo g){
        g= new Gizmo();
        g.spin();
    }
    void f(final int i){
    //  i++; 错误,无法改变final的值
    }
    int g(final int i){
        return i+1;
    }
    public static void main(String[] args) {
        FinalArgements faArgements = new FinalArgements();
        faArgements.with(null);
        faArgements.without(null);
    }
}
class Gizmo{
    public void spin() {
    }
}

final方法

为什么使用final方法?

1、将方法锁定,以防任何继承类修改它的含义,确保在继承中使方法行为保持不变,并不会被覆盖;
2、效率。

类中所有的private方法都隐式地指定为final的,但值得注意的是在基类和继承类中可以存在名称相同的方法,但也仅是名称相同而已,并不是类继承中所提到的“覆盖”。

final类

定义为final的类,是不允许被其他类继承的。

public class Jurassic {
    public static void main(String[] args) {

    }
}
class SmallBrain{}
final class Dinosar{
    int i = 7;
    int j = 9;
    SmallBrain xBrain = new SmallBrain();
    void f() {}
}

//Dinosar被定义为final类型的,无法被继承
// class Futher extends Dinosar {} 

注意:final类的域可以根据个人的意愿选择是或者不是final,由于final禁止继承,所以final类中所有的方法都隐式为final的。

类的初始化与加载

类的代码在初次使用时才加载,在访问static域和方法时,也会发生加载。另外类的构建器也是static方法,尽管static关键字并没有显式的写出来。

public class Beetle extends Insect{
    private int k = printInit("Beetle.k init!");
    public Beetle(){
        System.out.println("k = " + k);
        System.out.println("j = " + j);
    }

    private static int x2 = printInit("static Beetle.x2 init!");

    public static void main(String[] args) {
        System.out.println("Beetle constructor!");
        Beetle beetle = new Beetle();
    }
}
class Insect{
    private int i = 9;
    protected int j;
    public Insect() {
        System.out.println("i = " + i +",j= " + j);
        j = 39;
    }
    private static int x1 = printInit("static Insect.x1 init!");

    static int printInit(String s){
        System.out.println(s);
        return 47;

    }
}

执行结果:
static Insect.x1 init!
static Beetle.x2 init!
Beetle constructor!
i = 9,j= 0
Beetle.k init!
k = 47
j = 39

说明:在Beetle上运行java时,第一件事访问Beetle.main()方法,于是加载器开始启动并找出Beetle类的编译代码,(在名为Beetle.class文件中)。在加载过程中,发现它有一个基类,于是继续进行基类加载,此时不管是否产生一个该基类的对象,都要进行基类加载。
如果该基类还有基类,那么第二个基类也会被加载,如此类推。接下来,基类中的static初始化会被执行,然后是下一个继承类。这种方法是因为导出类的static初始化可能会依赖基类成员是否被正确初始化。
当必要类加载完毕,对象就可以被创建了。首先对象中的所有基本类型会被设置为默认值,对象引用被设置为null,然后基类构造器被调用,自动调用或使用super来指定。基类构造器先执行,导出类构造器后执行。
顺序:基类static变量->导出类static变量->基类构造器->导出类构造器

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值