java编程思想读书笔记-3

第6章 访问权限控制

6.4 类的访问权限

Java的访问权限控制修饰符,从最大权限到最小权限依次是:public、protected、包访问权限(默认,没有关键字)和private。对于类的访问权限只能是:public和包访问权限(但内部类可以是private或protected的);对于类中的成员的访问权限可以是上述的四种。下面是各种访问权限的作用。   

public修饰类

作用域当前类同一package普通类其他package普通类同一package子类其他package子类
public
protected×
默认×
×
×
private×
×
×
×
无修饰符(默认包访问权限)的类

作用域当前类同一package普通类其他package普通类同一package子类其他package子类
public×
×
protected×
×
默认×
×
private×
×
×
×

第7章 复用类

7.2.1 初始化基类

class Game {
	Game(int i) {
		System.out.println("Game constructor");
	}
}

class BoardGame extends Game{

	BoardGame(int i) {
		super(i);
		// TODO Auto-generated constructor stub
		System.out.println("BoardGame constructor");
	}
}

public class Chess extends BoardGame {

	Chess() {
		super(11);
		// TODO Auto-generated constructor stub
		System.out.println("Chess constructor");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Chess x = new Chess();
	}
}
如果不在BoardGame中调用基类构造器,编译器将“抱怨”无法找到符合Game形式的构造器。导出类构造器中要调用基类构造器。

7.3 代理

class SpaceShipControls{
	void up(int velocity){}
	void down(int velocity){}
	void left(int velocity){}
	void right(int velocity){}
	void forward(int velocity){}
	void back(int velocity){}
	void turboBoost(){}
}

class SpaceShip extends SpaceShipControls{
	private String name;
	public SpaceShip(String name){
		this.name = name;
	}
	
	public String toString(){
		return name;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SpaceShip protector = new SpaceShip("NESA Protector");
		protector.forward(100);
	}
}

public class SpaceShipDelegation {
	
	private String name;
	private SpaceShipControls controls = new SpaceShipControls();
	public SpaceShipDelegation(String name){
		this.name = name;
	}
	
	void up(int velocity){
		controls.up(velocity);
	}
	void down(int velocity){
		controls.down(velocity);
	}
	void left(int velocity){
		controls.left(velocity);
	}
	void right(int velocity){
		controls.right(velocity);
	}
	void forward(int velocity){
		controls.forward(velocity);
	}
	void back(int velocity){
		controls.back(velocity);
	}
	void turboBoost(int velocity){
		controls.turboBoost();
	}
	
	public static void main(String[] args) { 
		SpaceShipDelegation protector = new SpaceShipDelegation("NESA Protector");
		protector.forward(100);
	}
}
使用代理可以拥有更多的控制力,因为可以选择只提供在成员对象中的方法的某个子集。

7.4.1 确保正确清理

class Shape{
	Shape(int i){
		System.out.println("Shape constructor");
	}
	
	void dispose(){
		System.out.println("Shape dispose");
	}
}

class Circle extends Shape{
	Circle(int i){
		super(i);
		System.out.println("Drawing Circle");
	}
	
	void dispose(){
		System.out.println("Erasing Circle");
		super.dispose();
	}
}

class Line extends Shape{

	private int start, end;
	
	Line(int start, int end) {
		super(start); 
		this.start = start;
		this.end = end;
		System.out.println("Line: " + start + ", " + end);
	}
	
	void dispose(){
		System.out.println("Erasing Line: " + start + ", " + end);
		super.dispose();
	}
}

public class CADSystem extends Shape {
	
	private Circle c;
	private Line[] lines = new Line[3];
	
	CADSystem(int i) {
		super(i+1); 
		for(int j = 0; j < lines.length; ++j){
			lines[j] = new Line(j, j +1);
		}
		c = new Circle(1);
		System.out.println("CADSystem constructor");
	}
	
	public void dispose(){
		c.dispose();
		for(int j = 0; j < lines.length; ++j){
			lines[j].dispose();
		}
		super.dispose();
	}
	 
	public static void main(String[] args) { 
		CADSystem s = new CADSystem(47);
		try{
			//code ...
		}finally{
			s.dispose();
		}
	}
}
在清理方法(dispose)中,还必须注意对基类清理方法和成员对象清理方法的调用顺序,以防某个子对象依赖于另一个子对象情形的发生。垃圾回收器可能永远也无法被调用,即使被调用,它也极可能以任何它想要的顺序来收回对象,最好的办法是除了内存之外,不能依赖垃圾回收器去做任何事。如果需要进行清理,最好是编写自己的清理方法,但不要使用finalize()。

7.4.2 名称屏蔽

如果java的基类拥有某个已经被多次重载的方法名称,那么在子类中重新定义该方法名称并不会屏蔽其在基类中的任何版本。因此,无论在该层或者它的基类中对方法进行定义,重载机制都可以正常工作:

class Homer{
	char doH(char c){
		System.out.println("doH(char)");
		return 'd';
	}
	
	float doH(float f){
		System.out.println("doH(float)");
		return 1.0f;
	}
}

class Milhouse{ }

class Bar extends Homer{
	void doH(Milhouse m){
		System.out.println("doH(Milhouse)");
	}
}

public class Hide  {
	 
	public static void main(String[] args) { 
		 Bar b = new Bar();
		 b.doH(1);
		 b.doH('x');
		 b.doH(1.0f);
		 b.doH(new Milhouse());
	}
}
结果为:

doH(float)
doH(char)
doH(float)
doH(Milhouse)
Java SE5新增了@Override注解,它不是关键字,但可以当关键字使用。当你想覆写某个方法时,可以选择添加这个注解,在不小心重载而并非覆写了这个方法时,编译器就会生成错误信息。
class Bar extends Homer{
	@Override
	void doH(Milhouse m){
		System.out.println("doH(Milhouse)");
	}
}
会提示错误,The method doH(Milhouse) of type Bar must override or implement a supertype method

这样@Overrride注解可以防止你在不想重载时而意外地进行了重载。

7.7.2 再论组合与继承

在面向对象编程中,生成和使用程序代码最有可能采用的方法就是直接将数据和方法包装进一个类中,并使用该类的对象,也可以运用组合技术使用现有类来开发新的类,而继承不太常用。因此,虽然OOP中多次强调继承,但并不是说要多用继承,而是慎用继承。一个最清晰的判断搬到就是看是否需要新类向基类进行向上转型。如果需要,则继承是必要的,如果不需要则好好考虑是否需要继承。

7.8 final关键字

对于基本类型,final使数值恒定不变;而对于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法把它改为指向另一个对象。然而,对象本身却是可以被修改的。Java并未提供使任何对象恒定不变的途径,这一限制适用数组,它也是对象。

final参数

class Gizmo{
	public void spin(){}
}

public class FinalArguments {
	 
	void with(final Gizmo g){
		//g = new Gizmo();  //Illegal -- g is final
	}
	
	void without(Gizmo g){
		g = new Gizmo();
		g.spin();
	}
	
	//void f(final int i){ i++;} // can not change i
	int g(final int i){ return i+1;}
	
	public static void main(String[] args) { 
		FinalArguments fa = new FinalArguments();
		fa.with(null);
		fa.without(null);
	}
}
方法f()和g()展示了当基本类型的参数被指明为final时所出现的结果,可以读参数但是不能修改。这一特性主要用来向匿名内部类传递参数。

7.8.2 final方法

使用final方法的两个原因:1.把方法锁定,以防任何继承类修改它的含义2.确保在继承中使用方法行为保持不变,并且不会被覆盖。

在想要明确禁止覆盖时,才将方法设置为final的。

final类

将类整体设为final,表明不打算继承该类并且不允许别人这样做。final类禁止继承,所以类中的所有方法汇都隐式指定为final,因为无法覆盖他们,所以在final类中给方法加final修饰词是毫无意义的。

第八章 多态

8.2.1 方法调用绑定

绑定:

一个方法的调用与方法所在的类(方法主体)关联起来

前期绑定:

在程序执行之前方法已被绑定,此时由编译器或其他连接程序实现,例如:C。

后期绑定(动态绑定/运行时绑定):

在运行时根据对象的类型进行绑定

在java中,几乎所有的方法都是后期绑定的,在运行时动态绑定方法属于子类还是基类。但是也有特殊,针对static方法和final方法由于不能被继承,因此在编译时就可以确定他们的值,他们是属于前期绑定的。特别说明的一点是,private声明的方法和成员变量不能被子类继承,所有的private方法都被隐式的指定为final的(由此我们也可以知道:将方法声明为final类型的一是为了防止方法被覆盖,二是为了有效的关闭java中的动态绑定)。java中的后期绑定是有JVM来实现的,我们不用去显式的声明它,而C++则不同,必须明确的声明某个方法具备后期绑定。

8.2.2 产生正确的行为

import java.util.Random;

class Shape{
	public void draw(){}
	public void erase(){}
}

class Circle extends Shape{
	public void draw(){
		System.out.println("draw circle");
	}
	public void erase(){
		System.out.println("erase circle");
	}
}

class Square extends Shape{
	public void draw(){
		System.out.println("draw square");
	}
	public void erase(){
		System.out.println("erase square");
	}
}

class Triangle extends Shape{
	public void draw(){
		System.out.println("draw triangle");
	}
	public void erase(){
		System.out.println("erase triangle");
	}
}

class RandomShapeGenerator{
	private Random random = new Random(47);
	public Shape next(){
		switch(random.nextInt(3)){
		default:
		case 0: return new Circle();
		case 1: return new Square();
		case 2: return new Triangle();
		}
	}
}

public class Shapes {
	private static RandomShapeGenerator gen = new RandomShapeGenerator();
	public static void main(String[] args) { 
		Shape[] s = new Shape[9];
		for(int i = 0; i < s.length; ++i){
			s[i] = gen.next();
		}
		
		for(Shape shape:s){
			shape.draw();
		}
	}
}
结果是:

draw triangle
draw triangle
draw square
draw triangle
draw square
draw triangle
draw square
draw triangle
draw circle

8.2.4 缺陷:“覆盖”私有方法

普通方法才有多态,private方法由于被屏蔽,被默认为final方法。

域访问变量(getXXX)方法在编译期间被解析

8.2.5 缺陷:域与静态方法

class Super{
	public int field = 0;
	public int getField() { return field;}
}

class Sub extends Super{
	public int field = 1;
	public int getField() { return field;}
	public int getSuperFiedld(){ return super.field;}
}

public class FieldAccess {
	public static void main(String[] args){
		Super sup = new Sub();
		System.out.println("sup.field = " + sup.field  + ",sup.getField = " + 
		sup.getField());
		
		Sub sub = new Sub();
		System.out.println("sub.field = " + sub.field + ",sub.getFiled = " 
				+ sub.getField() + ",sub.getSuperField = " + sub.getSuperFiedld());
	}
}
结果是:
sup.field = 0,sup.getField = 1
sub.field = 1,sub.getFiled = 1,sub.getSuperField = 0
当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态的。上述例子中,为Super.field和Sub.field分配了不同的存储空间,这样Sub包含了2个称为field的域,它自己的和从Super得到的。因此在引用Sub中的field时,为默认自己的field,要用Super的field,须明确指明super.field。

class StaticSuper{
	public static String staticGet(){
		return "Base staticGet";
	}
	public String dynamicGet(){
		return "Base dynamicGet";
	}
}

class StaticSub extends StaticSuper{
	public static String staticGet(){
		return "Derived staticGet";
	}
	public String dynamicGet(){
		return "Derived dynamicGet";
	}
}

public class StaticPolymorphism {
	public static void main(String[] args){
		StaticSuper sup = new StaticSub();
		System.out.println(sup.staticGet());
		System.out.println(sup.dynamicGet());
	}
}
结果是:

Base staticGet
Derived dynamicGet
static方法是与类,而并非与单个的对象相关联的。

8.3 构造器和多态

8.3.1 构造器的调用顺序

1).调用基类构造器,这个步骤会不断地反复递归下去,首先是构造这种层次结构的根,然后是下一层子类,等等,最后是最底层的子类

2).按声明顺序调用成员的初始化发方法

3).调用导出类构造器的主体

8.3.2 继承与清理

销毁的顺序应该和初始化顺序相反。对于基类,应该是先对子类进行清理,然后是基类。这是因为子类的清理可能会调用基类中的某些方法,所以基类中的构件仍起作用而不应过早地被销毁。                           

8.3.3 构造器内部的多态方法的行为

初始化的实际过程:

1).在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的0。

2).如前所述调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0。

3).按照声明的顺序调用成员的初始化方法。

4).调用子类的构造器主体。

class Glyph{
	void draw(){
		System.out.println("Glyph.draw();");
	}
	Glyph(){
		System.out.println("Glyph() before draw");
		draw();
		System.out.println("Glyph() after draw");
	}
}

class RoundGlyph extends Glyph{
	private int radius = 1;
	
	RoundGlyph(int r){
		radius = r;
		System.out.println("RoundGlyph.RoundGlyph(), radius=" + radius);
	}
	void draw(){
		System.out.println("RoundGlyph.draw(), radius=" + radius);
	}
}

public class PolyConstructor {
	public static void main(String[] args){
		 new RoundGlyph(5);
	}
}
结果:

Glyph() before draw
RoundGlyph.draw(), radius=0
Glyph() after draw
RoundGlyph.RoundGlyph(), radius=5
编写构造器时有一条有效的准则:用尽可能简单的方法是对象进入正常状态,如果可以的话,避免调用其他方法。在构造器内唯一能够安全调用的那些方法是基类中的final方法(适用于private方法)。这些方法不能被覆盖,所以也不会出现上述的问题。

8.4 协变返回类型

在Java1.4及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值也必须完全一样。
Java5.0放宽了这一限制,只要子类方法与超类方法具有相同的方法签名,或者子类方法的返回值是超类方法的子类型,就可以覆盖。
注意:"协变返回(covariant return)",仅在subclass(子类)的返回类型是superclass(父类)返回类型extension(继承)时才被容许。

class Grain{
	public String toString(){
		return "Grain";
	}
}

class Wheat extends Grain{
	public String toString(){
		return "Wheat";
	}
}

class Mill{
	Grain process(){
		return new Grain();
	}
}

class WheatMill extends Mill{
	Wheat process(){
		return new Wheat();
	}
}

public class CovariantReturn {
	public static void main(String[] args){ 
		Mill m = new Mill();
		Grain g = m.process();
		System.out.println(g);
		m = new WheatMill();
		g = m.process();
		System.out.print(g);
	}
}

8.5 用继承进行设计

用继承表达行为之间的差异,并用字段表达状态上的变化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值