《Java语言程序设计(基础篇)》读书笔记(二)
书接上回,进入到重点章节。
第八章 对象和类
1、类方法
Java中用static关键字标识类方法,而在Objective-C中用加号(+)标识类方法;
需要说明的是,可运行类中的main方法必须是定义成public static void型的静态方法。
2、构造方法
构造方法具有以下特点:
①方法名必须和类名相同
形式如下:
public ClassName(arguments) { //init }
②没有返回类型
甚至连void类型都没有,一种常见的错误是:
public void ClassName() { }
③构造方法可以有若干个
同时有多个方法,在技术叫重载,同样也可以重载构造方法;
重载时除了遵守方法名和类名相同的规则以外,还要保证方法签名不同(只能通过给构造方法增加不同的参数来保证);
构造方法有多个就意味着我们可以通过多种方式创建一个对象;
所谓的若干,就是可以有多个,也可以一个都没有,就是说类也可以不定义构造方法,在这种情况下,编译器会生成一个隐藏的无参构造方法,注意是仅在我们没显示定义构造方法的情况下才生成。
④构造方法是实例方法
从构造方法的声明方式上不难看出这一点,之所以将其单列一条,是因为在Objective-C中可以通过两段构造法:先是类方法alloc来为对象分配内存,再通过实例方法init来初始化生成的对象(当然也支持直接使用类方法new来一步实现初始化对象),我实在好奇Java是如何通过实例方法直接初始化对象的!
⑤父类构造方法无法被子类继承
不像属性和方法,父类的构造方法是不能被子类继承的,它们只能从子类的构造方法中通过后文讲到的super关键字调用!这也是有别于Objective-C的一点。
第九章 字符串和文本I/O
1、字符串
Java中的字符串使用非基本类型变量String表示,它Objective-C中的NSString类功能相似。
需要说明的是,因为字符串是不可变的,但同时又会频繁地使用,所以Java虚拟机为了提高效率和节约内存,对具有相同字符串序列的字符串直接使用同一个实例,这是种在Cocoa中被称为享元模式的设计模式,Objective-C中的很多类比如NSString,NSNumber等都使用了这种模式
第十章 关于对象的思考
1、this引用
主要有两个作用:
①指代当前对象
Java以及很多语言中都有的关键字this和Objective-C中的关键字self非常相似,都用于指代当前对象
②让构造方法调用同一个类的另一个构造方法
这是Java中this比较特殊的用法。前面讲过构造方法也是可以重载的,当有多个构造方法的时候,通常无参数或者参数少的构造方法可以用this(参数列表)的方式调用参数多的构造方法。这跟Objective-C中指定初始化方法的设计原则很像,使用参数列表最多的作为指定初始化方法,其它参数较少的称为辅助初始化方法,辅助初始化方法通过调用指定初始化方法,并未没有显示要求的参数传入默认值来完成初始化操作。这样做可以简化代码,使类易于阅读和维护。以书上的Circle类为例:
public class Circle { private double radius; //指定构造方法 public Circle(double radius) { this.radius = radius; } //辅助构造方法 public Circle () { this(1.0);//通过this调用参数较多的指定构造方法 } }
第十一章 继承和多态
1、Java不支持多继承
和Objective-C一样,Java是不支持多继承的。
①Java和Objective-C多继承折中方案
Objective-C可以通过委托、协议、运行时消息分发等机制来弥补这个不足;
Java可以通过接口实现多继承,关于接口14章中会详细介绍。
②Java中接口和Objective-C中协议的异同
相同点:
我理解的Java中的接口有点像Objective-C中的协议,它们都是为了定义一种类所具有的能力,都是为了使方法从某些具有相同能力的、具体的类中抽象出来;
不同点:
二者有本质的区别,Objective-C中的协议充其量只是一个方法集合,而Java中的接口却是特殊的抽象类,其本质是类!
2、super关键字
类似Objective-C中的super关键字,Java中的super也是指向当前类的父类,它的特殊用法是用于调用父类的构造方法
前面讲过,super是显示调用父类构造方法的唯一方式,而且这个调用必须是子类构造方法的第一条语句,如下所示:
public Circle2 (double radius, boolean filled) { super(filled);//调用父类的构造方法,必须放在子类构造方法的第一句 this.radius = radius; }
3、类继承中的构造方法链
在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法,这就是构造方法链。关于构造方法链有以下说明:
①自动调用父类无参构造方法
当前类的构造方法需要调用重载的构造方法或者父类的构造方法,如果二者都没有显示调用,编译器会自动将super()作为当前构造方法的第一条语句,来调用父类的无参构造方法,比如:
public ClassName() { //some statements }
等价于:
public ClassName() { super(); //some statements }
再强调一遍,只会自动调用父类的无参构造方法!
②编译器会为没有显式定义构造方法的类自动生成隐式的无参构造方法
注意这句话的前提是当前类没有显式定义构造方法!
③要为每个类提供一个无参构造方法
结合前面的①、②两条,不难解释本条。举例说明:
public class Apple extends Fruit { } class Fruit { public Fruit(String name) { System.out.println("Fruit's constructor is invoked."); } }
实例化Apple对象时,由于在Apple中没有显示定义构造方法,因此,编译器为Apple生成的隐式默认无参构造方法会被调用。因为Apple是Fruit的子类,Apple的默认构造方法会自动调用Fruit的无参构造方法。然而Fruit中显示定义了重载的构造方法,编译器就不会自动为其生成无参构造方法,这样就会导致程序编译错误!
总之,出现问题的原因是Fruit类没有定义无参构造方法。
因此,如果一个类要设计成扩展的,最好提供一个无参构造方法以避免程序设计错误,
4、覆盖方法
子类可以从父类中继承方法,但有时子类需要修改父类中方法的实现,这就叫方法的覆盖。关于方法覆盖有几点需要注意:
①覆盖父类的方法有时需要调用父类的方法,可以通过super.被覆盖方法名的方式实现,如下:
public class Circle4 extends GeometricObject { //other methods are omitted /**Override the toString method defined in GeometricObject*/ public String toString() { return super.toString + "\nradius is" + radius; } }
②仅当实例方法是可访问时,它才能被覆盖
因为私有方法在它的类本身以外是不能访问的,所以它不能被覆盖。如果子类中定义的方法在父类中是私有的,那这两个方法就没有任何关系。
③静态方法不能被覆盖
和实例方法一样,静态方法也能被继承,但不同的是它不能被覆盖。如果父类中定义的静态方法在子类中被重新定义,那么在父类中的静态方法将被隐藏。可以使用语法:父类名.静态方法名来调用隐藏的父类静态方法。
④Java中的覆盖和Objective-C中的重载
Objective-C中的方法重载(又叫重写)和紧接着要讲的Java方法重载意义不同,却和Java中的方法覆盖差不多。
5、重载方法
重载方法意味着可以定义多个同名的方法,但这些方法需要具有不同的方法签名。
重载和覆盖的区别:
①覆盖对应的两个方法名和方法签名均相同;重载对应的两个方法名相同,但方法签名不同
②覆盖对应的两个方法一个在子类中,一个在父类中;重载对应的两个方法可能都在子类,也可能一个在子类一个在父类。
6、Java的根类Object和他的toString()方法
①Object类
Java中的每个类都源自java.lang.Object类,如果定义一个类时没有指定继承性,那么这个类的父类就被默认为是Object。
Java中的Object类和Objective-C中的NSObject类相似。
②toString()方法
该方法是Object类的实例方法,会返回一个描述该对象的字符串;
Java中Object的toString()方法和Objective-C中NSObject中的实例方法- (NSString *)description功能相似。
7、动态绑定
①声明类型
一个变量必须被声明成某种类型,变量的这个类型称为它的声明类型
②实际类型
变量的实际类型是变量引用对象的实际数据类型
这里想说明的是,变量的声明类型决定了编译时匹配那种类型,用于编译器检查语法错误,而运行时会将该变量作为实际类型来使用,变量类型检查放到运行时进行,这也是判断一门语言是不是动态语言最最根本的标准!!!众所周知,静态语言的变量类型检查是在编译阶段就完成的。
8、对象类型判断
Java语言的动态性,使得一个对象可能并不是它实际声明的类型,判断一个对象的真实类型可以通过java关键字instanceof实现。
该关键字和Objective-C中NSObject的实例方法:- (BOOL)isKindOfClass:(Class)aClass功能相似。
注意Java是通过关键字来实现,Objective-C是通过NSObject实例方法来实现的。
9、数据和方法的可见性
见下图所示:
10、防止扩散和覆盖
①终极类
有时候可能希望防止类扩展,在这种情况下可以使用final修饰符表明一个类是终极的,比如Java中的Math就是一个终极类,是不能作为父类的。终极类声明方式如下:
public final class ClassName { }
②终极方法
也可以将方法定义为终极的,一个终极方法是不能被它的子类覆盖的。终极方法声明方式如下:
public class ClassName { //Data fields ,constructors and methods omitted public final void foo { } }
③终极变量
变量也可以定义为终极的,结果是其就成了常量。
好吧,都快一点了,明天还要上班,抓紧睡觉
未完待续。。。