final数据
final数据只可以在定义时初始化,或者是在声明blank final后在构造函数中初始化。对于基本类型,final域值不可变,对于引用类型,
final的引用指向不可变,但是其引用所指向的对象的属性其实是可变的。
final 数据可以被继承的,并且可以被子类同名属性覆盖,参看示例:
public class SuperAttribute {
public final String str = "父类的final属性";
public final String strNotHide = "父类的final属性 没有被隐藏的 可以被子类继承的";
}
public class SubAttribute extends SuperAttribute {
public final String str = "子类的final属性";
@Test
public void test() throws Exception {
//父类引用指向子类对象 属性是不存在多态性的
SuperAttribute supera = new SubAttribute();
System.out.println(supera.str);//输出 父类的final属性
SubAttribute sub= new SubAttribute();
System.out.println(sub.str);//输出 子类的final属性
System.out.println(sub.strNotHide);//父类的final属性 没有被隐藏的 并且这个final属性是可以继承的
}
}
final参数
Java允许在参数列表中以声明的方式将参数指明为final。这样就无法在方法中更改参数引用所指向的对象。这一特性主要用来向匿名内部类传递数据。
final方法
现在使用final方法的原因只有一个:把方法锁定,以防止任何继承类修改他的含义,想要确保继承中使方法行为保持不变,
并且不会覆盖。记住,final方法的含义只有一个:方法不可被子类改变(重写override和覆盖隐藏hiding)
对于实例方法final的含义为:在子类中不可以重写这个方法
对于静态方法final的含义为: 在子类中不可以隐藏(覆盖)这个方法
示例代码如下:
public class SuperFinalMethod {
public final void finalMethod(){
System.out.println("父类的final方法");
}
public static void staticFinalMethod(){
System.out.println("父类的static final方法");
}
public static final void staticFinalMethodNotHide(){
System.out.println("父类的static final方法 没有覆盖");
}
public static void main(String[] args) {
}
}
public class SubFinalMethod extends SuperFinalMethod{
/**
* Cannot override the final method from SuperFinalMethod
* 实例final方法是不可以被override(重写)的,方法签名一致就不可以
public final void finalMethod(){
System.out.println("父类的final方法");
}
*/
/**
* 实例final方法虽然不可以被重写,但是在子类中可以重载这个final方法
*/
public final void finalMethod(int i){
finalMethod();//从父类中继承了
System.out.println("父类的final方法");
}
//隐藏(覆盖)父类的静态方法
public static void staticFinalMethod(){
System.out.println("子类的static final方法");
}
/**
* <b>不可以通过编译</b>
*
* 编译器给出的提示信息:
* SubFinalMethod 中的 staticFinalMethodNotHide() 无法覆盖 SuperFinalMethod 中的
* staticFinalMethodNotHide();被覆盖的方法为 static final
*
*Eclipse给出的提示信息是错误的:Cannot override the final method from SuperFinalMethod
*staticFinalMethodNotHide()方法是静态的,不可以重写(),只能覆盖,但是又由于staticFinalMethodNotHide()方法是
*final的,所以也无法覆盖。
*
*所以final对于实例方法和静态方法的含义是不同的
*对于静态方法final的含义是不可覆盖(不可隐藏 can't hiding)
*对于实例方法final的含义是不可重写override
*总之final方法含义就是子类继承的这个方法不可变(不可重写,不可隐藏覆盖)
public static final void staticFinalMethodNotHide(){
System.out.println("父类的static final 方法是无法覆盖的");
}
*/
}
final和private关键字
类中所有的private方法都隐式的指定为final的。由于无法取用private方法,所以也就无法覆盖它。(private方法在继承类中
是无法使用的,自然也就没有覆盖之说了)
但是下面的情形可能会引起一些疑惑。
class WithFinals {
// Identical to "private" alone:
private final void f() {
System.out.println("WithFinals.f()");
}
// Also automatically "final":
private void g() {
System.out.println("WithFinals.g()");
}
}
class OverridingPrivate extends WithFinals {
private final void f() {
System.out.println("OverridingPrivate.f()");
}
private void g() {
System.out.println("OverridingPrivate.g()");
}
}
class OverridingPrivate2 extends OverridingPrivate {
public final void f() {
System.out.println("OverridingPrivate2.f()");
}
public void g() {
System.out.println("OverridingPrivate2.g()");
}
}
public class FinalOverridingIllusion {
private static Test monitor = new Test();
public static void main(String[] args) {
OverridingPrivate2 op2 = new OverridingPrivate2();
op2.f();
op2.g();
// You can upcast:
OverridingPrivate op = op2;
// But you can't call the methods:
//! op.f();
//! op.g();
// Same here:
WithFinals wf = op2;
//! wf.f();
//! wf.g();
monitor.expect(new String[] {
"OverridingPrivate2.f()",
"OverridingPrivate2.g()"
});
}
} ///:~
"覆盖"只有在某方法是基类的接口的一部分时才会出现。即,必须能将一个对象向上转型为它的基本类型并调用相同的方法。
如果某个方法为private,它就不是基类接口的一部分。如果在导出类中以相同的名称生成一个public,protected,defualt
方法,则只是生成了一个新的方法。与是否覆盖并没有关系。
另外,对于覆盖,必须方法签名一致才是覆盖,如果方法签名不一致,比如方法参数不同,也存在覆盖。如下所示:
public class FinalObj {
void defaultFinalMethod(String str) {
System.out.println(" defaultFinalMethod " + str);
}
public final void protectedfinalMethod(String str) {
System.out.println(" FinalObj protected final " + str);
}
public void protectedMethod(String str) {
System.out.println(" FinalObj protected " + str);
}
}
public class FinalObjSub extends FinalObj {
@Override
public void protectedMethod(String str) {
System.out.println(" FinalObjSub protected " + str);
}
/**
@Override 无法通过编译,因为父类中不存在这个方法,也没有覆盖之说
public void protectedMethod(int str) {
System.out.println(" FinalObj protected " + str);
}
*/
}
final类
当将某个类整体定义为final时,就表明你不打算继承该类,而且也不允许别人这么做。换句话说,你对该类的设计用不需要
做出任何变动,或者是出于安全考虑,你不希望它有子类。
静态方法的继承,但并不存在重写(覆写 override)
静态方法是可以继承的,但是在子类中即使可以定义一个与父类方法签名相同的方法会覆盖掉父类的方法,但是这并不是重写
重写应该体现在多态性上有所体现,但是覆盖父类静态方法并不会体现多态性。看看下面的实例代码:
public class SuperStaticObj {
public final void finalMethod(){
System.out.println(" super finalMethod");
}
public void method() {//普通实例方法 体现多态性,可以由子类继承并可以重写override
System.out.println("fatherMethod");
}
//静态方法,不体现多态性,可以由子类继承,但是不可以重写(orverride),只可以覆盖
public static void staticMethod() {
System.out.println("fatherStaticMethod");
}
public static void staticMethodNotHide() {
System.out.println("fatherStaticMethodNotHide");
}
}
public class SubStaticObj extends SuperStaticObj {
@Override
public void method() {
System.out.println("SubMethod");
}
/**
*父类中也存在相同的方法签名的staticMethod()方法,在子类中定义一个与父类相同方法签名的
*静态方法这种方式并不是覆写,而只是隐藏(覆盖)了父类的静态方法,如果是覆写的话,那么在父类引用指向
*子类对象时,对象会表现出多态性
*请参考test4Static()方法
*/
public static void staticMethod() {
System.out.println("SubStaticMethod");
}
/**
*可以直接在子类中调用父类的静态方法,说明父类的静态方法是继承了的
*/
public static void staticMethodFromSuperType() {
staticMethodNotHide();
}
@Test
public void test4Static() throws Exception {
//父类引用指向子类对象
SuperStaticObj sso = new SubStaticObj();
sso.method();//输出SubMethod 调用的运行时子类的方法
sso.staticMethod();/**
输出 fatherStaticMethod 虽然父类引用指向的是子类对象,但是仍然调用的是父类的方法
**/
}
/**
* 在子类中直接调用被隐藏的父类的static方法,会调用这个类中的使父类方法隐藏的那个新方法
*/
@Test
public void test4StaticHide() throws Exception {
staticMethod();//SubStaticMethod
}
}
属性存在继承,但没有重写
属性存在继承性,但是却不表现多态性,也就是说属性可以继承不可重写,可以覆盖
多态仅针对实例方法,与实例的属性无关。重写只对方法有效,对属性无效!示例代码:
public class SuperAttribute {
public int i = 0;
public int j = 0;
public void printI(){
System.out.println(" 父类 i = " + i +" ,j = " +j);
}
}
public class SubAttribute extends SuperAttribute {
//覆盖了父类的i属性i = 0
public int i = 1;
public void printI(){
System.out.println(" 子类 i = " + i +" ,j = " +j);
}
@Test
public void test4AttributeCover() throws Exception {
//对于属性i 和 j存在继承
super.printI();//i = 0 ,j = 0
printI();//i = 1 ,j = 0
//多态性的验证 父类引用指向子类对象
SuperAttribute sa = new SubAttribute();
sa.printI();//子类 i = 1 ,j = 0 方法具有多态性
System.out.println("i = " + sa.i);//i=0属性不具备多态性,因此也没有重写之说,只是覆盖了父类的同名属性
}
}
继承方法访问属性时
假设子类从超类中继承了一个方法,在这个方法中需要访问一个属性,即使这个属性在子类中重新被覆盖,那子类对象调用这个父类方法
时仍然访问的是父类的属性。除非在子类中重写父类方法,这样才会访问子类的属性。示例如下:
public class SuperAttribute {
public int i = 0;
public int j = 0;
public void printI(){
System.out.println(" 父类 i = " + this.i +" ,j = " +this.j);
}
public void printJ(){
System.out.println(" 父类 i = " + this.i +" ,j = " +this.j);
}
}
public class SubAttribute extends SuperAttribute {
//覆盖了父类的i属性i = 0
public int i = 1;
public void printJ(){
System.out.println(" 子类 i = " + this.i +" ,j = " +this.j);
}
@Test
public void test4AttributeCover() throws Exception {
//父类引用指向子类对象
SuperAttribute sa = new SubAttribute();
sa.printI();// 父类 i = 0 ,j = 0 访问的是父类的属性
sa.printJ();//子类 i = 1 ,j = 0 override printJ()之后访问的是子类的属性
//子类引用指向子类对象
SubAttribute sub = new SubAttribute();
sub.printI();// 父类 i = 0 ,j = 0 访问的是父类的属性
sub.printJ();//子类 i = 1 ,j = 0 override printJ()之后访问的是子类的属性
}
}
author by zhaob
time : 2014-09-13 14:18
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。