您的位置:首页 > 编程语言 > Java开发

JAVA里一直想实验的几个小问题

2016-04-04 00:28 603 查看

1、父类型引用指向子类型对象,只能调用父类有的方法,不能调用子类独有的方法。输出结果取决于子类实例到底什么样。

<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.*;

class A {
void f1() {
println("a");
}
}

public class B extends A {

void f1() {
println("b");
}

void f2() {
println("bbbb");
}

public static void main(String[] args) {
A a = new B();
a.f1();
//! a.f2();   这是错误的!A类型引用根本无法调用f2()
}
/*
Output:
b
*///:~

}
</span>

2、关于跨包继承,是否能重写,是否能调用的实验:

项目目录:



A.java:
<span style="font-family:Microsoft YaHei;">package com.cry.another;

import static com.cry.utils.Print.println;

public class A {

protected void f1(){
println("a");
}

}
</span>


B.java:

<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import com.cry.another.A;

import static com.cry.utils.Print.*;

public class B extends A {

// 重写父类的方法总是可行的,不管父类中该方法是什么访问权限。
// 但要保证子类中该方法的访问权限大于等于父类
protected void f1() {
println("b");
}

public void f2() {
f1();   //这样调用正确

//! A a = new A();
//! a.f1();     错误,你不能调用另一个A类对象的f1(),因为f1()是protected的。
}

public static void main(String[] args) {
B b = new B();
b.f2();
}
/*
Output:
b
*///:~

}
</span>


3、只要是用final修饰的数据,初始化之后就再也不能更改,不管是在什么地方,什么访问权限。只要是final修饰的变量在声明时就必须明确的初始化。

<span style="font-family:Microsoft YaHei;">class A {
//    final int v;  //ERROR!

private final int v1 = 1;
protected final int v2 = 1;
public final int v3 = 1;
final int v4 = 1;

public void f() {
//        v1 = 2;   //ERROR!
//        v2 = 2;   //ERROR!
//        v3 = 2;   //ERROR!
//        v4 = 2;   //ERROR!
}</span>


4、父类的private成员,子类不能直接访问,但是如果父类有public修饰的getter/setter,子类则可以直接使用。比如下面的例子,可以说明,一个子类实例中确实包含一个名为val的int型数据实体,一个子类实例实际上包含一个父类实例在其中,但是父类的private修饰部分,子类却无法直接访问。面向对象的程序设计中,我们应当持这样的态度:“我们除了把private部分看成该类内部的实现结构之外,其他任何时候都不必考虑另一个类的private”。(注:JAVA的@Override注解似乎对这一问题有奇妙作用,日后研究)。或者可以说,private将类与类之间完全隔离开,哪怕它们是父子类。

<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.println;

class A {
private int val;

public int getVal() {
return val;
}

public void setVal(int val) {
this.val = val;
}
}

public class B extends A {

//    val = 5;  //ERROR!

void f() {
//        val = 5;  //ERROR!
setVal(1);
}

public static void main(String[] args) {
B b = new B();
b.f();
println(b.getVal());
b.setVal(5);
println(b.getVal());
}
}
/*
Output:
1
5
*///:~</span>


5、final方法,子类根本不能重写,但子类可以调用。也就是说子类仍具有该final方法,只不过该方法的含义截止在父类那“一代”,子嗣无法修改。这满足了设计中这样的需求:锁定一个方法,以防止任何继承类修改它的含义,确保了该方法在继承中行为不变且不被覆盖。

<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.println;

class A {
public final void f(){
println("AAA");
}
}

public class B extends A{
//    public void f(){} //ERROR!编译器直接报错,final方法不能被子类重写

public static void main(String[] args) {
B b = new B();
b.f();  //但是子类可以使用这个final方法,这是没问题的。
}
}
/*
Output:
AAA
*///:~</span>


6、private修饰的东西别的类就是不能访问到,子类也不能访问到,“同名重写覆盖”它,其实编译器只是认为子类有了一个新方法。

package com.cry.practice;

import static com.cry.utils.Print.*;

class Son extends Father{
public void f(){
println("son");
}
}

public class Father {
private void f(){
println("father");
}

public static void main(String[] args) {
Father o1 = new Father();
Father o2 = new Son();
Son o3 = new Son();

o1.f();
o2.f();
o3.f();
}
/*
Output:
father
father
son
*///:~
}


7、关于抽象类的一个基本小例子, 注意其数据访问权限和初始化顺序。

记住三不相容:
1、abstract不能与private同用,因为private不可被子类访问,也不可被重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract是需要被重写的抽象方法。

2、abstract不能与final同用,因为final修饰的不能被重写,而abstract是需要被重写的抽象方法。

3、abstract不能与static同用,static修饰的方法归该类所有而非某个具体对象,并且也只归该类所有。如果该方法是protected或public,子类可以继承或调用,但不能重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract表示期望被子类实现,所以不可同时使用。

package com.cry.practice;

import static com.cry.utils.Print.*;

//如果包含抽象方法,那这个类在声明时就必须用abstract修饰,否则IDE报错。
abstract class Student {
public String type = "student";
public abstract void introduce();
}

public class Tom  extends Student{

public static void main(String[] args) {
Tom tom = new Tom();
tom.introduce();
}

//如果一个非抽象类继承了抽象类,那就必须给出抽象方法的定义。
@Override
public void introduce() {
//抽象类也是类,其中已经具体定义的数据成员可以访问,其子类的整个初始化过程也按标准进行。
println("Tom is a " + type);
}
/*
Output:
Tom is a student
*///:~
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 基础 对象