[200128]Java学习内容整理 - Thinking in Java学习日志

每个类都可以创建main函数

说明

在Java中,可以为每一个类创建一个main()方法,这使得测试每个类变得简单易行,而且在测试过后也无需删除main(),可以留待下次测试。即使一个程序中包含多个类,也只有命令行所调用的那个类的main()方法会被调用;即使这个类只有包访问权限,这个类的main()方法也可以被调用。

示例

以两个不同包的编译单元为例:

package com.phycanva.demonstrate;

public class Multimain {
	public static void main(String[] args) {
		System.out.println("public类主函数");
	}

}
class Multimain_package{
	public static void main(String[] args) {
		Multimain.main(args);
		System.out.println("包访问权限类主函数");
	}
}
package com.phycanva.demonstrate.assist;
import com.phycanva.demonstrate.*;

public class Multimain_out {
	public static void main(String[] args) {
		Multimain.main(args);
		//!Multimain_package.main(args);	//错误:不在同一个包内,不可见
	}
}

我所使用的IDE是Eclipse。
在运行时如果一个编译单元中有多个类,可以选择其中的一个类进行运行,如下图:
选择一个类
在访问权限范围内,类可以调用其他类的main()函数。
我们不妨把“类”当成运行的目标,而把“main()”当成一个特殊的方法:它既有作为一般public static方法的特性,也是运行类的入口。

代理

说明

Java没有对代理的直接支持,但可以进行手动实现。代理是继承和组合的中庸之道:我们像组合一样把一个成员对象置于所要构造的类中;与此同时我们像继承一样,在新类中暴露了该成员对象的所有方法。

示例

package com.phycanva.demonstrate;

public class ControlCenter {
	void command1() {
		System.out.println("指令1");
	}
	void command2() {
		System.out.println("指令2");
	}
}

class Machine{
	ControlCenter cc = new ControlCenter();
	void command1() {
		cc.command1();
	}
	void command2() {
		cc.command2();
	}
	public static void main(String[] args) {
		Machine m = new Machine();
		m.command1();
		m.command2();
	}
}

通过手动构造两个方法来达到暴露接口的目的。

final关键字

final关键字的含义通常为“无法改变的”,使用final通常出于两种不同的考虑:设计和效率。

final数据

我们使用final来向编译器告知一块数据是恒定不变的

  • 一个永不改变的编译时常量
  • 一个在运行时被初始化、且恒定的值

当final修饰的常量为编译期常量的情况,编译器可以将该常量值代入所有用到它的地方(类似于C语言的宏)来进行优化;这类常量必须是基本数据类型,并且在定义时就要为其赋值。
当final运用于对象引用的时候,只能使引用的指向不变,而不能使引用指向的对象保持不变。

static final

当final和static连用时,数据会兼备static和final关键词所赋予的特性:

  • 定义static:强调数据只有一份
  • 定义为final:强调数据是一个常量

根据惯例,既是static、又是final的域(即编译期常量)应用大写表示,使用下划线分隔单词(这点和C中的常量相似)。

误区警示

注意:我们不能因为数据是final的,就认为可以在编译期间知道它的值
例如:

private static final int RAD = rand.nextInt(20);

显然只有在运行时,才可以确定RAD的确定值。

空白final

所谓“空白final”是指被声明为final却没有赋予初值的域,所以看上去好像没有被初始化一样。但是无论什么情况,编译器都能确保空白final在使用之前必须初始化
编译器确保final必须在两个地方进行初始化

  • 在域的定义处(非空白final)
  • 在每个构造器中(空白final)

final参数

说明这个参数是不能更改,即在这个方法中赋予参数只读的特性(这与C、C++中形参加const类似)
这一特性只要用于向匿名内部类传递数据

final方法

使用final的方法的原因有二:

  • 设计方面:把方法锁定,防止任何继承类修改它的含义
  • 效率方面:提高效率

private方法与final方法

对于方法而言,final和private有神似之处:final不允许继承类修改它的含义;private不允许被继承。因为不能被继承,所以不存在含义被修改的情况,即:所有的private方法都隐性地被指定为是final的

误区警示

当我们试图通过继承来覆盖一个private方法的时候,似乎没什么毛病(编译器也不会报错),但是我们并没有真正覆盖成功。

package com.phycanva.demonstrate;

public class Father_fakeInherit {
	protected void f1() {System.out.println("父类 f1");}
	
}

class Son_fakeInherit extends Father_fakeInherit {
	public void f1() {System.out.println("子类 f1");}
	public static void main(String[] arg ) {
		Son_fakeInherit s = new Son_fakeInherit();
		s.f1();
		Father_fakeInherit f = s;
		f.f1();
	}
}

当被继承方法为protected时,父类中定义的方法被覆盖,输出:

子类 f1
子类 f1
package com.phycanva.demonstrate;

public class Father_fakeInherit {
	private void f1() {System.out.println("父类 f1");}
	
}

class Son_fakeInherit extends Father_fakeInherit {
	public void f1() {System.out.println("子类 f1");}
	public static void main(String[] arg ) {
		Son_fakeInherit s = new Son_fakeInherit();
		s.f1();
		Father_fakeInherit f = s;
		f.f1();
	}
}

将protected更改为private时,在调用时出现错误:

The method f1() from the type Father_fakeInherit is not visible

表示父类实例无法从外部调用f1()方法,这就说明了父类的f1()没有被覆盖(如果被覆盖了,应该成功调用子类public的f1()方法)
“覆盖”仅在某方法是父类的接口的一部分时才会出现。即:必须能将一个对象向上转型为它的基本类型,并调用相同的方法。如果某方法是private,它就不是父类接口的一部分,即private方法无法被继承,它仅是所在类内部的一部分

final类

当一个类被整体定义为final的时候,表明这个类无法被继承,所以类中所有的方法都被隐式地指定为final,在final类中给方法加final修饰,要么是为了提高可读性,要么纯属闲得蛋疼。

后记

由于仍处于学习阶段,文章中的内容很可能不够准确也不够全面。文中若有错误出现,敬请指出,一定虚心改正;有需要补充修改的地方,也请各位不吝赐教,十分乐意与大家交流学习。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值