第七章:复用类

第七章:复用类

复用代码

​ 复用代码在编程语言中是非常重要的部分,减少代码的臃肿和冗余。Java中常见的复用代码有两种,不破坏现有类的代码,因为已经经过调试①组合:在新类中产生现有类的对象,从而调用现有类的方法,达到复用效果(方法是public修饰或同包)。②继承:继承现有类型,直接添加新代码或者对父类方法进行覆盖

组合是讲现有类型作为新类型的底层实现加以复用,而继承复用的是接口

一、 组合语法:
class Soap {
    
      	//下列数字表示执行顺序(静态变量、静态方法、成员常量、构造代码块、构造方法)
  private String s;
  Soap() {
    
    
    print("Soap()");
    s = "Constructed";
  }
  public String toString() {
    
     return s; }
}	

public class Bath {
    
    
  private String // Initializing at point of definition: 1、定义出初始化
    s1 = "Happy",
    s2 = "Happy",
    s3, s4;
  private Soap castille;
  private Soap soap = new Soap();  //2、定义出初始化
  private int i;
  private float toy;
  public Bath() {
    
    
    print("Inside Bath()");
    s3 = "Joy";
    toy = 3.14f;
    castille = new Soap(); //4、构造中初始化
  }	
  // Instance initialization:
  {
    
     i = 47; } //3、构造代码块初始化,也称实例初始化
  public String toString() {
    
    
    if(s4 == null) // Delayed initialization: 5、延迟初始化
      s4 = "Joy";
    return
      "s1 = " + s1 + "\n" +
      "s2 = " + s2 + "\n" +
      "s3 = " + s3 + "\n" +
      "s4 = " + s4 + "\n" +
      "i = " + i + "\n" +
      "toy = " + toy + "\n" +
      "soap = " + soap + "\n" +
      "castille = " + castille;
  }
  public static void main(String[] args) {
    
    
    Bath b = new Bath();
    print(b);
  }
} /* Output:
Soap()
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
soap = Constructed
castille = Constructed
*///:~
二、 继承语法:

1、继承基类的所有,也可以覆盖成员,也可以扩展域变量和方法

2、构造方法中含有一句默认的super调用父类的构造,先父类初始化,后子类初始化

class Cleanser {
    
    
  private String s = "Cleanser";
  public void append(String a) {
    
     s += a; }
  public void dilute() {
    
     append(" dilute()"); }
  public void apply() {
    
     append(" apply()"); }
  public void scrub() {
    
     append(" scrub()"); }
  public static void  test(){
    
     print("test");}
  public String toString() {
    
     return s; }
  public static void main(String[] args) {
    
    
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    print(x);
  }
}	

public class Detergent extends Cleanser {
    
    
  //静态方法 可以被继承,但是不能被重写,如果父子类静态方法名相同,则会隐藏父类方法。
  public static void  test(){
    
     print("test_01");}
  // Change a method:重写、覆盖原方法
  public void scrub() {
    
    
    append(" Detergent.scrub()");
    super.scrub(); // Call base-class version 是呀super调用父类方法,放在构造方法中,必须放在首行
  }
  // Add methods to the interface:
  public void foam() {
    
     append(" foam()"); }
  // Test the new class:
  public static void main(String[] args) {
    
    
    Detergent x = new Detergent();
    x.dilute();
    x.apply();
    x.scrub();
    x.foam();
    print(x);
    print("Testing base class:");
    Cleanser.main(args);
    Detergent.test();
  }	
} /* Output:
Cleanser dilute() apply() Detergent.scrub() scrub() foam()
Testing base class:
Cleanser dilute() apply() scrub()
test
test_01   
*///:~

三、代理:

代理就是包装具体实现,类似于租房(可以做前后操作)

public class GetResultProxy {
    
    
	private Calculater cal = new Calculater();
	public long GetSum(){
    
    
		System.out.println("代理前操作");
		return cal.Sum();
        System.out.println("代理后操作");
	}
	public static void main(String[] args) {
    
    
		GetResultProxy result = new GetResultProxy();
		System.out.println(result.GetSum());
	}
}
/*output
use proxy
499500
*/
四、protected:

protected运行子类访问(不同包之间也行)父类或同包之间互相访问

class Villain {
    
    
  private String name;
  protected void set(String nm) {
    
     name = nm; }
  public Villain(String name) {
    
     this.name = name; }
  public String toString() {
    
    
    return "I'm a Villain and my name is " + name;
  }
}	

public class Orc extends Villain {
    
    
  private int orcNumber;
  public Orc(String name, int orcNumber) {
    
    
    super(name);
    this.orcNumber = orcNumber;
  }
  public void change(String name, int orcNumber) {
    
    
    set(name); // Available because it's protected 基类方法是protected修饰的
    this.orcNumber = orcNumber;
  }
  public String toString() {
    
    
    return "Orc " + orcNumber + ": " + super.toString();
  }	
  public static void main(String[] args) {
    
    
    Orc orc = new Orc("Limburger", 12);
    print(orc);
    orc.change("Bob", 19);
    print(orc);
  }
} /* Output:
Orc 12: I'm a Villain and my name is Limburger
Orc 19: I'm a Villain and my name is Bob
*///:~

组合和继承什么环境使用:

需要向上转型时使用继承,不需要则建议组合语法

五、final关键字

含义:无法改变的,为设计和效率考虑

1、final修饰的数据

①编译时不变的常量 ②运行时被初始化的值,都不希望改变,所以使用final修饰

作用:编译时将常量替换到计算式中,这样可以减轻运行时的负担

使用:①该成员变量在定义处或构造中就初始化(赋值),不然报错

​ ②static final 修饰的类型常量,大写命名。多个单词之间下划线分隔__

​ ③static和final修饰的域,是一段不可能改变的存储空间,并且随着该类的加载而初始化,创建对象是无法改变的

​ ④final修饰的基本类型,其值恒定不变;final修饰的引用类型,保证该引用只能指向该对象不变,而对象自身却可以改变(包括数组)。

class Value {
    
    
  int i; // Package access 	包访问权限
  public Value(int i) {
    
     this.i = i; }
}

public class FinalData {
    
    
  private static Random rand = new Random(47);
  private String id;
  public FinalData(String id) {
    
     this.id = id; }
  // Can be compile-time constants:  可编译时常量
  private final int valueOne = 9;
  private static final int VALUE_TWO = 99; //编译时静态基本类型常量,大写命名
  // Typical public constant:
  public static final int VALUE_THREE = 39;
  // Cannot be compile-time constants:  运行时常量
  private final int i4 = rand.nextInt(20);	//运行时初始化的常量,每次运行都可初始化一次,生成一个新值
  static final int INT_5 = rand.nextInt(20); //装载时初始化,不可每次创建对象时初始化
  private Value v1 = new Value(11);
  private final Value v2 = new Value(22);
  private static final Value VAL_3 = new Value(33);
  // Arrays:
  private final int[] a = {
    
     1, 2, 3, 4, 5, 6 };
  public String toString() {
    
    
    return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
  }
  public static void main(String[] args) {
    
    
    FinalData fd1 = new FinalData("fd1");
    //! fd1.valueOne++; // Error: can't change value 常量不可变
    fd1.v2.i++; // Object isn't constant! 	改变的是对象中成员
    fd1.v1 = new Value(9); // OK -- not final 没有被final修饰
    for(int i = 0; i < fd1.a.length; i++)
      fd1.a[i]++; // Object isn't constant! 改变的是对象中的值,并没有改变引用
    //! fd1.v2 = new Value(0); // Error: Can't 错误
    //! fd1.VAL_3 = new Value(1); // change reference  不能改变指向的地址
    //! fd1.a = new int[3]; 不能改变指向的地址
    print(fd1);
    print("Creating new FinalData");
    FinalData fd2 = new FinalData("fd2");
    print(fd1);
    print(fd2);
  }
} /* Output:
fd1: i4 = 15, INT_5 = 18
Creating new FinalData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
*///:~

关于final修饰成员定义处未初始化:

class Poppet {
    
    
  private int i;
  Poppet(int ii) {
    
     i = ii; }
}

public class BlankFinal {
    
    
  private final int i = 0; // Initialized final 已初始化
  private final int j; // Blank final 未初始化
  private final Poppet p; // Blank final reference 未初始化引用
  // Blank finals MUST be initialized in the constructor: 空白final必须初始化在构造中
  public BlankFinal() {
    
    
    j = 1; // Initialize blank final
    p = new Poppet(1); // Initialize blank final reference
  }
  public BlankFinal(int x) {
    
    
    j = x; // Initialize blank final
    p = new Poppet(x); // Initialize blank final reference
  }
  public static void main(String[] args) {
    
    
    new BlankFinal();
    new BlankFinal(47);
  }
} ///:~
2、final 修饰方法

原因:锁定方法,让继承的子类无法重写该方法

class WithFinals {
    
    
  // Identical to "private" alone: 基类中的方法被private修饰,有隐藏的final修饰的意识,隐藏于类中,子类同名并不是覆盖,而是一个新方法
  private final void f() {
    
     print("WithFinals.f()"); }
  // Also automatically "final":   private是隐士的final
  private void g() {
    
     print("WithFinals.g()"); }
}

class OverridingPrivate extends WithFinals {
    
    
  private final void f() {
    
     //子类的同名方法,并未覆盖
    print("OverridingPrivate.f()");
  }
  private void g() {
    
    
    print("OverridingPrivate.g()");
  }
}

class OverridingPrivate2 extends OverridingPrivate {
    
    
  public final void f() {
    
     //子类的同名方法,并未覆盖
    print("OverridingPrivate2.f()");
  }
  public void g() {
    
    
    print("OverridingPrivate2.g()");
  }
}

public class FinalOverridingIllusion {
    
    
  public static void main(String[] args) {
    
    
    OverridingPrivate2 op2 = new OverridingPrivate2();
    op2.f();
    op2.g();
    // You can upcast:
    OverridingPrivate op = op2;
    // But you can't call the methods:
    //! op.f();
    //! op.g();
    // Same here:
    WithFinals wf = op2;
    //! wf.f();
    //! wf.g();
  }
} /* Output:
OverridingPrivate2.f()
OverridingPrivate2.g()
*///:~

在这里插入图片描述

3、final 修饰的类

final修饰的类,不希望继承,不需要改动,不希望有子类

如果类别final修饰,那么成员无需final修饰,没意义

六、初始化及类的加载

1、类的加载通常由两种情况:①第一次创建该类的对象 ②访问了该类的static成员

运行Beetle.main()方法,展现程序执行顺序(在代码中数字体现顺序):每个构造器中有句隐士的super();

class Insect {
    
    
  private int i = 9;	// 6、父类成员变量初始化为9,按照代码先后顺序
  protected int j;	    // 7、j初始化为0
  Insect() {
    
    		   // 8、构造方法运行
    print("i = " + i + ", j = " + j); // 10、输出 i = 9, j = 0
    j = 39;				// 11、j赋值为39
  }
  private static int x1 = printInit("static Insect.x1 initialized");//2、静态域(成员变量)初始化,按照代码先后顺序   
  static int printInit(String s) {
    
    			// 3、由于静态成员变量初始化调用执行,x1=47
    print(s);
    return 47;
  }
}

public class Beetle extends Insect {
    
    
  private int k = printInit("Beetle.k initialized"); // 12、成员变量初始化为47
  public Beetle() {
    
    	// 13、构造方法运行
    print("k = " + k);
    print("j = " + j);	// 继承于基类
  }
  private static int x2 = printInit("static Beetle.x2 initialized");// 4、子类静态成员变量初始化,调用父类静态方法 
  public static void main(String[] args) {
    
       //1、运行main方法
    print("Beetle constructor");	// 5、运行静态方法		
    Beetle b = new Beetle();		// 14、对象初始化完成
  }
} /* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*///:~

猜你喜欢

转载自blog.csdn.net/jue6628/article/details/104207566