概述
Java中复用类主要使用的的方法有两种。
第一种是直接在一个新的类中产生以前类的对象,由于新的类是现有类的对象组成,因此这种方法成为组合,注意该方法只是使用了现有类中程序代码的功能,并没有复用其形式。
第二种是按照现有类的类型来创建新类,并且沿用现有类的形式,而且可以在现有类的形式中添加新的代码。这种方式称为继承。继承是面向对象程序设计的基石之一。
1 组合
组合语法是我们最经常用到的,就是将对象引用置于新类中,然后进行初始化,一般来说,我们可以在代码中的四个位置进行初识化:
- 在定义对象的地方就初始化,这种方式在构造器被调用之前就完成了初始化。
- 在类的构造器中。
- 什么时候需要使用这些对象什么时候初始化,这种方式称为惰性初始化。在生成对象不值得且不必每次都生成对象的情况下,这种方式可以减少额外的负担。
- 使用实例初始化。
以下是这四种方式的测试代码:
package com.thinkjava.reusing;
/**
* Bath.java
* @description 进行初始化的四个位置
* @author Trigl
* @date 2016年1月20日下午8:58:03
*/
class Soap {
private String s;
Soap() {
System.out.println("Soap()");
s = "Constructed";
}
public String toString() { return s; }
}
public class Bath {
private String // 在定义对象的地方初始化
s1 = "Happy",
s2 = "Happy",
s3,s4;
private Soap castille;
private int i;
private float toy;
public Bath() {
System.out.println("Inside Bath()");
s3 = "Joy";
toy = 3.14f;
castille = new Soap(); // 在构造器中初始化
}
{ i = 47; } // 实例初始化
public String toString() {
if(s4 == null) //惰性初始化
s4 = "Joy";
return
"s1 = " + s1 + "n" +
"s2 = " + s2 + "n" +
"s3 = " + s3 + "n" +
"s4 = " + s4 + "n" +
"i = " + i + "n" +
"toy = " + toy + "n" +
"castille = " + castille;
}
public static void main(String[] args) {
Bath b = new Bath();
System.out.println(b);
}
}
/* Output:
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
*/
在上面的例子中,注意一个方法的用法:toString()。每一个非基本类型的对象都有一个toString()方法,而且当编译器需要一个String而你只有一个对象时,该方法就会被调用。
2 继承
继承语法首先是通过在类主题的左边花括号之前,书写关键字extends加上基类名称来声明“新类与旧类相似”。这样,就会自动得到基类的所有域和方法。例如:
package com.thinkjava.reusing;
/**
* Detergent.java
* @description 继承语法
* @author Trigl
* @date 2016年1月20日下午9:12:45
*/
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 String toString() { return s; }
public static void main(String[] args) {
Cleanser x = new Cleanser();
x.dilute(); x.apply(); x.scrub();
System.out.println(x);
}
}
public class Detergent extends Cleanser {
//改变一个方法
public void scrub() {
append(" Detergent.scrub()");
super.scrub(); // 调用基类版本
}
//添加一个方法
public void foam() { append(" foam()"); }
//测试新类
public static void main(String[] args) {
Detergent x = new Detergent();
x.dilute();
x.apply();
x.scrub();
x.foam();
System.out.println(x);
System.out.println("测试基类:");
Cleanser.main(args);
}
}
/* Output:
Cleanser dilute() apply() Detergent.scrub() scrub() foam()
测试基类:
Cleanser dilute() apply() scrub()
*/
这个程序示范了Java的许多特性。首先,Cleanser和Detergent都含有main()方法。我们可以为每一个类创建一个main()方法,这样方便进行测试。并且即使一个程序中含有多个类,也只有命令行所调用的那个类的main()方法会被调用。例如在此例中,如果命令行打出的是:Java Detergent,那么Detergent.main()将会被调用。如果命令行打出的是:Java Cleanser,那么Cleanser.main()将会被调用,即使Cleanser不是一个public类。在本例中,可以看到Detergent.main()明确调用了Cleanser.main(),并将从命令行获取的参数传递给了它。当然,也可以传递任意的String数组。
其次,注意Cleanser中所以的方法都必须是public的,这一点非常重要。如果没有加任何的访问权限修饰词,那么成员默认的访问权限是包访问权限,仅允许包内的成员访问。但是在这种情况下,如果其他包中的某个类想要从Cleanser中继承,则只能访问public成员。所以,为了实现继承,一般的规则是将所以的数据成员都指定为private,将所有的方法指定为public。
第三,在Cleanser的接口中有这样一组方法: append( ), dilute( ), apply( ), scrub( )和 toString( ),由于Detergent是由关键字extends从Cleanser中导出的,所以它可以在其接口中自动获得这些方法,尽管并没有在Detergent看到定义它们。因此,可以将继承看作是对类的复用。
第四,正如scrub()方法所见,可以对基类中定义的方法进行修改。在此例中,我们还想要在新版本中调用从基类中继承而来的原始方法,但是在scrub()中,并不能直接调用scrub(),因为这样会产生递归,此时,super关键字就起作用了,这个关键字表示超类的意思,因此,使用super.scrub()来调用基类版本的scrub()方法。
最后,在继承的过程中并不一定非得使用基类中的方法,也可以在新类中添加新方法,如本例的foam()方法。
2.1 创建导出类对象时构造器的调用顺序
当创建导出类的对象时,由于要继承基类接口中的域和方法,所以实际上该对象还包含了一个基类的子对象。这个子对象与你用基类直接创造的对象是一样的,二者的区别在于,后者来自于外部,而基类的子对象则是被包装在导出类对象内部。
Java会自动在导出类的构造器中插入对基类构造器的调用,当然你自己也可以手动进行调用。下面的例子展示了上诉机制在三层继承关系上是如何工作的:
package com.thinkjava.reusing;
/**
* Cartoon.java
* @description 在继承时调用构造器
* @author Trigl
* @date 2016年1月20日下午10:12:43
*/
class Art {
Art() { System.out.println("Art constructor"); }
}
class Drawing extends Art {
Drawing() { System.out.println("Drawing constructor"); }
}
public class Cartoon extends Drawing {
public Cartoon() { System.out.println("Cartoon constructor"); }
public static void main(String[] args) {
Cartoon x = new Cartoon();
}
}
/* Output
Art constructor
Drawing constructor
Cartoon constructor
*/
我们会发现,构造过程是从基类“向外”逐层扩散,这样保证基类在导出类构造器可以访问它之前就已经完成了初始化。
最后
以上就是敏感纸飞机为你收集整理的复用类的两种机制1 组合2 继承的全部内容,希望文章能够帮你解决复用类的两种机制1 组合2 继承所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复