【Java编程思想】(3)复用类

1. 每一个非基本类型的对象都有一个toString()方法,而且当编译器需要一个String而你却只有一个对象时,该方法便会被调用。


2. 构造方法的过程是从基类“向外”扩散的,所以基类在导出类构造方法可以访问它之前,就已经完成了初始化。

调用父类构造方法必须是你在导出类构造方法中要做的第一件事。


3. 子类要想覆盖基类的方法,必须方法名,参数和返回值3个都一直才可以覆盖,否则编译不通过。


4. 由导出类转型成基类,在继承图上是向上移动的,因此一般称为向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所有总是很安全的,也就是说,导出类是基类的一个超级。它可能比基类含有更多的方法,但它必须至少具备基类中的所含有的方法。在向上转型的过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取它们。这就是为什么编译器在“未曾明确表示转型”或“未曾指定特殊标记”的情况下,仍然允许向上转型。


5. 根据上下文环境,Java的关键字final的含义存在着细微的区别,但通常它指的是”这是无法改变的。”不想做改变可能出于两种理由:设计或效率,由于这两个原因相差很远,所以关键字final有可能被误用。使用到final的三种情况:数据、方法和类。

在Java中,当以关键字final修饰时,必须对其进行赋值(或者在构造方法中赋值),否则编译不通过。必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。

一个既是static又是final的域只占据一段不能改变的存储空间。

当对对象引用而不是基本类型运用final时,其含义会有一点令人迷惑。对于基本类型,final使数值恒定不变;而用于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的,Java并未提供使任何对象恒定不变的途径(但可以自己编写类以取得使对象恒定不变的效果)。这一限制同样适用数组,它也是对象。

我们不能因为某数据是final的就认为在编译时可以知道它的值。在运行时使用随机生成的数值来初始化就说明了这一点。

public class TestFinal {
	private static Random rand = new Random(47);
	private String id;

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

	private final int valueOne = 9;
	private static final int VALUE_TWO = 99;
	public static final int VALUE_THREE = 39;
	public static 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);
	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) {
		TestFinal tf1 = new TestFinal("tf1");
		// fd1.valueOne++; // Error: can't change value
		tf1.v2.i++; // Object isn't constant !
		tf1.v1 = new Value(9); // ok -- not final
		for (int i = 0; i < tf1.a.length; i++) {
			tf1.a[i]++; // Object isn't constant !
		}
		// tf1.v2 = new Value(0); // Error: can't;
		// tf1.VAL_3 = new Value(1); // change reference.
		// tf1.a = new int[3];
		System.out.println(tf1);
		System.out.println("Creating new TestFinal");
		TestFinal tf2 = new TestFinal("tf2");
		System.out.println(tf1);
		System.out.println(tf2);
	}
}

class Value {
	int i;

	public Value(int i) {
		this.i = i;
	}
}

也可以传递null当参数给方法:

public class TestFinalMethod {

	void with(Gizmo g) {
		g = new Gizmo();
		System.out.println("创建好了!" + g.i);
	}

	public static void main(String[] args) {
		TestFinalMethod tfm = new TestFinalMethod();
		tfm.with(null);
	}
}

class Gizmo {
	int i = 4;
}

如果with的参数是final Gizmo g,那么就会在方法第一行报错了。

使用final方法的原因有两个:第一个原因是把方法锁定,以防止任何继承类修改它的含义。过去使用final的第二个原因就是效率。

类中所有的private方法都隐式地指定为是final的,由于无法取用private方法,所以也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。

“覆盖”只有在某方法是基类接口的一部分时才会出现,即,必须能将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是基类的接口的一部分,它仅是一些隐藏于类中的程序代码,只不过是具有相同名称而已。如果在导出类中以相同的名称生成一个public、pretected或宝访问权限方法的话,该方法就不会产生在基类中出现的“仅具有相同名称”的情况。此时你并没有覆盖该方法,仅是生成了一个新的方法。

final类的域可以根据个人的意愿选择是或不是final,不论类是否被定义为final,相同的规则都适用于定义为final的域,然而,由于final类禁止继承,所以final类中所有的方法都是隐式指定为是final的。


6. 初始化过程

父类静态方法(父类静态代码块)-->子类静态方法(子类静态代码快)-->父类成员(父类代码块)-->父类构造方法-->子类成员(子类代码块)-->子类构造方法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值