java复用类



java复用类。

If you can’t fly then run,if you can’t run then walk, if you can’t walk then crawl,but
whatever you do,you have to keep moving forward——Martin Luther King.

复用类这标题刚开始很难懂,后面专门去看了书的英文原版,其实标题是reusing classes,重新使用类,其实复用就是“利用现成的东西”的意思,其实实现的两种方法就是java中经常听到的——组合和继承。

(1)组合
has-a的作用。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class TV {
Show show;
public String toString(){
return “showgirl”;
}
}

class Show{
}

提一下toString方法,当你需要String而你是一个对象的时候,编译器会调用对象的toString方法。
TV里有Show,现在的show没有初始化,为null,不能调用show的方法。

组合的作用强大,以面向对象看,假如你在造一个Car类,那么你可以用组合轻易的将Glass,Light,Engine等等的Car这些部件组合起来。

(2)继承
is-a
[java] view plaincopy在CODE上查看代码片派生到我的代码片
package com.myown.iaiti;

public class Father {
public int i;
void get(){
System.out.println(“father”);
}
}

package son;
import com.myown.iaiti.*;

public class Son extends Father{
Father f = new Father();
int j = f.i;
Son son = new Son();
son.get();
}

public void get(){
super.get();
System.out.println(“son”);
}
}

这里有个包访问权限的问题,假如没有加public的时候,默认是包内成员访问,不同包访问,即Son中的Father成员访问get方法是不可见的。而public的话是可见的,所以i访问得到。

private部分是不能继承,属于父类私有,而public的部分,将继承,需要修改的方法,可以进行重写。要添加的属性可以单独添加。

而且继承的方法,如果原本的father的public方法重写之后没将public加上,会有Cannot reduce the visibility of the inherited method from Father,也就是不能减少父类中继承方法的可见性。super指的是父类,即Father。

还有一点是,其实java中所有的类都隐式地继承了Object类。Object是父类,其他类是子类
老外喜欢讲为基类。子类也叫导出类或者派生类。

(3)代理
设计模式里面有个比较难懂的——代理模式,作者讲的很有趣,代理是组合和继承的中庸之道。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
package son;
class Father{
public void get(){
System.out.println(“father”);
}
}
public class Son extends Father{
public static void main(String[] args) {
Father f = new Father();
f.get();
}
}

class FatherProxy{
private Father f = new Father();
public void get(){
f.get();
}
}

像直接把Father当做成员,那么father的方法就暴露给这个类了,那我们可以使用FatherProxy这样的代理类,我自己定义好get方法是怎么拿的,我自己知道是调用father的get方法,但是使用我这个代理的人不知道,我只告诉他你要用就用代理的get的方法就可以了。封装性就体现出来了。上面只是随便敲的一个简单例子。

(4)重写和重载
[java] view plaincopy在CODE上查看代码片派生到我的代码片
class Father{
public void get(String s){
System.out.println(“father”);
}

public void get(boolean b){
System.out.println(“boolean”);
}
}
public class Son extends Father{
@Override
public void get(String s){
System.out.println(“father”);
}


// @Override //会有错误提示 因为父类没有该方法,不是重写
public void get(int i ){
System.out.println(“sonint”);
}

public static void main(String[] args) {
Son s = new Son();
s.get(“d”);
s.get(false);
s.get(1);
}
}

重写是重新覆盖父类的方法,如果没有重写或者重载,那么子类调用一个子类没有的方法时,其实是调用父类。

重载是同样的方法名,但参数名称不同,为了防止你错误的进行重载可以加上@Override标签,那样会提示你并没有重写方法。

(5)protected
Java编程思想(三) —— 访问权限的控制
在前面一篇提前写了,因为之前没讲继承的东西。

可以简单将protected看成父类给儿子继承的遗产,其他非继承类不能访问。

(6)final关键字
加上final关键字的基本类型,表示这个变量初始化后不会改变。类似c的define,你希望一个变量在这个程序里就是这个值不需要改变。就可以用final。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class Son{
int age = 2;
public static void main(String[] args) {

final int i = 1;
// i = 2; 值不能再改变
final Son son = new Son();
// son = new Son();
//The final local variable son cannot be assigned.
//It must be blank and not using a compound assignment
//final修饰的局部变量son不能被分配,必须为空或者不要再次分配

son.age = 4;
//虽然引用恒定不变,但是,对象本身却可以改变。
}

void change(final int c){
// c= this.age; 无法赋予新值 因为值只有在方法传参决定 对象引用和这个类似
//age ++; 无法改变
}
}

static本来是静态初始化,和final一起用就是占据了一块不能改变的存储空间。
static final即编译期常量,常量名按照c的常量命名传统,全部用大写字母,单词之间用下划线分开。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
static final VALUE_ONE = 1;

final修饰方法时
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class Print {
final void cannotprint(){
System.out.println(1);
}
}

public class PrintSon extends Print{
//void cannotprint(){}
//无法重写 因为被final修饰了

public static void main(String[] args) {
PrintSon ps = new PrintSon();
ps.cannotprint();
}
}

可以看成父类要求子类必须继承的不可修改财产(祖传)。private隐式地指定为final,因为private根本就不给你继承。这比给你继承但不能修改还更私有。

顺便将权限理清。
public,公共财产,不止是子类,其他类也可以用。
final,祖传珍宝,留给子类,但不允许修改。
private,父类私有财产,不会给子类继承。
protected,父类专门留给子类的财产,其他人不能用它。

当final修饰的是类的时候,是为了让这个类不会被继承。

(7)继承和初始化
这里的顺序问题是一个很有趣的问题。看例子。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
class GrandFather{
private static int i = print();
private static int print(){
System.out.println(“g”);
return 1;
}
}
class Father extends GrandFather{
private static int i = print();
private static int print(){
System.out.println(“f”);
return 1;
}
}
public class Son extends Father{
private static int i = print();
private static int print(){
System.out.println(“s”);
return 1;
}
public static void main(String[] args) {
System.out.println(“first”);
}
}

打印的结果是first吗?错了。
虽然执行的是main方法,但是看到son这个需要静态初始化的i没有,结果是s,first吗?
这还有初始化的问题,son是继承father,那么编译器会加载father,并初始化i,那father继承grandfather,那么编译器会去加载grandfather,类似递归。
那最后最先初始化的是grandfather的i。
所以最后的结果是:g,f,s,first。

至于这章提到的向上转型,是和多态联系着的,所以放到下一篇来讲。
面向对象的三大基本特性之一 —— Java编程思想(五) —— 多态。