1.     类的成员
1)     Field,字段
定义: 类的数据变量。
作用: 持有类/对象的状态。
修饰符(请用以下顺序进行声明):
annotations,本章不予讨论。
access modifiers,下文讨论。
static,下文讨论。
final,下文讨论。
transient,串行化讨论。
volatile,同步/内存模型时讨论。
一个字段不能同时为final和volatile。
Static 字段:
       Static字段是类变量。每个实例只存一个副本。访问Static字段时请使用类名,避免使用实例名。
Final 字段:
       当Final字段被初始化后,该字段只读。作用是在类/对象生命期间,为类/对象定义一个永恒的特性。Final字段一般被用来定义命名常量。
       Final字段在多线程的并发访问中也有特殊的语义。
       Final字段如果是基本类型或String类型,那么该字段就是一个命名常量,在编译时将常量值编译进字节码中。所以,如果该常量有变,需重新编译。
       如果将引用类型的字段声明为final的话,那么该字段不指向任何其他变量,但可能改变对象的内容,因为只有引用本身是final的。
 
2)     Method,方法
定义:类的可执行代码。
作用:定义类的行为。
方法的签名:方法名+ 参数列表
方法的修饰符:
annotations
access modifiers
abstract
static
final
synchronized
native
strict floating point
An abstract method cannot be static, final, synchronized, native, or strict. A native method cannot be strict.
Static 方法:
static方法是类方法。类方法是执行一项对所有对象都通用的任务。
类方法只能存取static字段和static方法,因为static方法内不存在this指针,所以无法存取非static成员。
参数:
Java参数传递是“值”传递。
对于“基本类型”,值传递后不改变实参的值;但是,对于“引用类型”,这是要注意的,可能改变,原来的对象本身的值。
序列参数:可变数目的参数,即传递某一类型的0或多个参数。
如:public void Foo( String… param1);
编译器本质上构造了一个数据param1[];
自动参数类型转换:实参初始化形参的时候,低类型项高类型自动转换,包装类向基本类型转换,基本类型向包装类转换等。
方法的执行与返回:
返回:return语句;方法体结束;异常被抛出;
返回值必须是返回类型或与返回类型兼容(可赋值给返回类型的变量)。
方法与封装:
用private修饰字段(状态),用方法来存取该字段。
this 引用
this 引用只存在于非static方法中;它代表当前对象的引用;
方法重载
方法名相同,但是参数列表不同,此时,方法重载生效。简言之,只要方法签名不相同,那么重载就生效。
对于序列参数,因为序列参数就是数组参数,所以,相同类型的数组参数与序列参数是等价的,不属于不同的签名。
对于相同类型的参数列表,方法重载可能会发生错误的,尤其有序列参数,并且序列参数的类型与其他类型又一致。如下例:
public static void print(String title) {
    // ...
}
public static void print(String title, String... messages) {
    // ...
}
public static void print(String... messages) {
    // ...
}
print("Hello"); // which print ?
print("Hello", "World"); // INVALID: ambiguous invocation,Compiler ERROR
要改变上述的错误,只要调用的时候指明参数类型即可:
print("Hello", new String[] {"World"});
print( new String[] { "Hello", "World" });
固定参数列表的方法的优先级高于有序列参数的方法。至于调用重载后的方法,JVM是如何选择方法,见方法选择一节。
Native 方法:
方法由非Java语言所写;或者要直接操纵硬件的话,可以使用Native方法。
Native方法可以被声明为final, static, synchronized, public, protected, or private.,可以重载,可以重写;
就是不能被声明为abstract或者strictfp。
使用Native方法,使Java代码丧失了可移植性和安全性。
Native方法用C来写的标准是JNI(Java Native Interface)。
final 方法:
final方法不能够被重写。
final方法是inline方法,同样,private 和 static 方法也是inline方法,因为这些方法不用运行时绑定。
3)     Nested Class/interface,嵌套类/嵌套接口
类/接口中内嵌的另一个类/接口的定义。在本文中有专门一节讲述嵌套类。
 
2.     类的修饰符与访问控制
1)     annotations,注解
注解在专门的一章中讲述。本文略。
2)     public
任何人都可以访问该类。
缺省类修饰符的情况下,该类的访问范围只在该类的同一个包内。
3)     abstract
抽象类不能有实例。
含有抽象方法的类是抽象类。
 
4)     final
final类不能有子类。且final类中的方法都是final方法。
有助于安全性。
有了final类,很多类型检查可以在编译时搞定。
5)     strict floating point,strictfp
3.     创建对象
使用关键字NEW创建对象,如果系统没有空间分配给对象那么会运行GC来回收空间,然后再分配,如果此时仍没有足够的空间的话,new操作抛出OutOfMemoryError异常。
当new构造一个新对象时,构造方法被调用,但是在此之前,字段已经被初始化(意思是:字段要么显示被初始化要么隐式初始化为空值(0、false或null));
缺省无参构造方法的访问控制级别与该类相同。
若自行定义了构造方法,则,缺省无参构造方法无效。
显示构造方法调用
       在一个构造方法内可以调用另一个构造方法,只是把构造方法的名字换成了this。但是要注意的是,this(arg1,arg2,…)必须出现在构造方法的最前面。并且, 参数不准为引用当前对象的任何成员(字段或方法),因为,当前对象还不存在。
初始化块
       初始化块用于初始化字段,出现在类的字段声明、方法、构造器之外。初始化块就好像出现在 每个构造方法最开始处一样,多个初始化块的话,以其在类中声明的次序出现在构造方法中。
       当 所有的构造方法都声明了某个 相同的异常,初始化块也会抛出该异常。
       初始化块在匿名内部类很有用;
同样,初始化块是所有构造方法都执行的代码的一个公用块,当然一般情况下,可以把这段公用代码块写在一个init方法中,然后由构造方法调用,可是,这和初始化块是有很大区别的,初始化块的语义是初始化,所以,可以在初始化块内给final字段赋值,而在init方法内是不允许这么做的。
Static 初始化块
即:Static字段的初始化块。由关键字static声明,块中只能是static字段,并且无法抛出异常。
Static的初始化块是在类被加载后执行的,并且只执行一次,所以,在该初始化块中可以使用类的任何成员。
如果类X的Static初始化块要调用Y中的方法,同时Y的Static初始化块要调用X中的方法。那该怎么办呢?那么X的Static初始化器会执行到调用Y的方法的那个地方,任何X中的static字段没有执行它的初始化块中的代码的话,都会含有该字段类型的默认值(0, null, false,’/u0000’)。
4.     类的继承
1)     构造过程
构造器不是方法,构造器不能继承,构造器只能调用。所以每个类的构造器必须自己定义而不能妄想从父类借用过来。
子类的不仅继承了父类的状态(字段),而其可以拥有自己的状态。子类自己的状态由其构造器完成初始化,而继承了的父类的状态却只能由父类自行完成初始化。所以,子类会隐式或显式地 调用父类的构造器来完成构造。
显式调用:使用关键字 super
隐式调用:如果在子类构造器的首句未出现 super或者 this构造器调用(意思是既没有调用父类的构造器,也没有调用自己的构造器),那么编译器会自动把 super()插入第一行,super()是无参父类构造器。如果父类没有无参构造器的话,必须显示调用,否则编译器报错。由于构造器是无法继承的,所以,即使继承链中基类有无参构造器也没有办法不让最亲父子关系的父类不写无参构造器,即必须写无参构造器,否则,显式调用。
2)     构造顺序
第一步:分配存储空间给类的字段,包括继承了的父类的字段。
第二步:把这些字段的值设为其类型对应的缺省值。
第三步:进入构造器:
(1)   调用父类的构造器。
(2)   初始化字段[执行字段的初始化程序]和执行初始化块。
(3)   执行构造器体。
递归地执行第三步直到java.lang.Object对象为止。
首先是如(1)所示,如果是显式this构造器调用的话,调用链会找到父类构造器调用为止。显式父类构造器调用的参数不允许含有当前对象的成员。
在(2)中,允许引用当前对象的成员作为表达式的一部分,进行初始化。
 
构造过程中如果发生异常的话,new操作中指,并且不返回任何对象的引用。因为(1),所以在构造器中catch异常是不可能的,只能在new的时候catch。
 
理解构造顺序是重要的,当在构造阶段调用方法时,字段的值就可以很清楚被了解。
构造器应当避免调用可重写的方法(非private、static、final方法),当你调用这些方法的时候,必须在文档中说明,以免发生逻辑错误。
 
3)     继承细节
重写——方法
一个方法能够被重写,当且仅当该方法是可访问的,比如某方法是private,其子类虽然与该方法的签名相同,但是这两个方法根本无关。
public A foo()//父类中的方法
public B foo()//子类重写父类的方法
签名相同,实现细节不同,注意:返回值类型是:
(1)   引用类型:返回值类型B,可以是A类型,也可以是A类型的子类。
(2)   基本类型:返回值类型必须相同(A==B)。
同样,throws子句也是一样的。子类抛出的异常必须是父类抛出的一场列表中的一个,并且异常类型必须与父类的异常类型多态兼容[同上(1)]。换言之,子类的异常列表不但比父类的更具体而且可以少于父类异常列表,甚至没有throws子句。
对于序列参数,本质上与数组参数一致,可以在重写方法的时候,把最后一个参数是数组参数的参数替换为序列参数,但这里不推荐这么做。
 
子类重写父类的方法的访问权限必须是大于等于父类的该方法的权限,比如,父类是protected,子类重写后可以改为public或protected,但是不能改为缺省的或者private。
还有一点要说明的是:实例方法的签名必须与继承了的static方法不一致,反之亦然。
方法的参数可以被声明为final,如:public A foo(final int a);然而,final不是方法签名的一部分,所以子类重写的方法可以删去这个final或者添加没有final的父类的方法的参数为final,原因就是final是实现的部分的细节。
隐藏——字段
子类声明了与父类同名的字段(与类型无关,仅仅标识符相同),那么子类无法直接通过字段名字访问父类的同名字段,称子类隐藏了父类的字段。
访问被继承的成员
       设B是A的子类,main方法如下:
B b = new B() ;
A a = b ;
对于方法,是多态调用,即运行时绑定,即a.foo() 与 b.foo()调用到同一个方法;
对于字段,是静态调用,即编译时绑定;
如果A中有一个字段名叫x(假设public),B中也有个字段叫x(假设public),那么a .x返回的是A中的那个字段值,而b.x返回的是B中的字段值,即使a和b引用到同一个对象上。
这点是要注意的,所以一般是把字段修饰为private,通过方法来访问字段;但这也不是通用的方法,具体要看语义。
Static 成员的继承
static成员永远不能被重写,静态成员只能被 隐藏 / 遮蔽[如果没有同名的静态成员,则继承使用父类的static,如果有的话,遮蔽父类的static成员]。所以要使用static成员必须通过声明这些static成员的类的类名调用。如果使用实例引用去访问static方法的话,那么访问到的成员不是多态的,即静态调用,编译时决定(根据该引用声明时的类型)。
super 引用
super引用可以出现在任何非static方法中。可以把super引用看作是当前类的父类的一个实例。
protected 的内涵
泛泛地讲,protected成员能够被其子类访问。更精确一点,除了能 被其自身的类访问( this 引用)以及能够被 同一个包内的代码(类引用)访问以外,protected成员也可以通过该类(或该类的子类)的引用访问到。
看下面的说明代码:
package myA ;
Class A {
protected int a ;
protected void printA(){
              System.out.println(a);
}
}
package myB ;
Class B extends A {
       void foo(B b){ // 这里通过 B 类引用访问 protected 成员,当然, b 如果是 B 的子类型也是可以的。
// 但是,如果 b A 类型,那么编译器出错。如果 B A 在同一个包中,那么
// 编译成功,因为同一个包中, protected 成员可访问。
                                      // 原因是,这里的 protected 成员是 B 的成员,与 A 没有关系了。
              System.out.println(b.a);
}
}
protected static 成员在继承类中可以被任意使用,因为static 成员不能被重写,只可以被遮蔽,所以static 成员就是声明它的类的版本,不存在子类的版本,所以不会违背父类的契约。
java 中类的限定词的作用范围比较
 
同一个类
同一个包
不同包的子类
不同包非子类
private
*
 
 
 
default
*
*
 
 
protected
*
*
*
 
public
*
*
*
*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值