首先先解决掉上一篇我个人遗留的疑问:
1、java 访问控制关键字作用范围
public 一般称作公共权限,其限制最小,也可以说没有限制,使用public 修饰的内容可以在其它所有位置访问,只要能访问到对应的类,就可以访问到类内部public 修饰的内容,一般在项目中开放的方法和构造方法使用public 修饰,开放给项目使用的类也使用public 修饰。
protected 一般称作继承权限,使用protected 修饰的内容可以被同一个包中的类访问也可以在不同包内部的子类中访问,一般用于修饰只开放给子类的属性、方法和构造方法。
private 一般称作私有权限,其限制最大,类似于文件中的绝密,使用private 修饰的内容只能在当前类中访问,而不能被类外部的任何内容访问,一般修饰不开放给外部使用的内容,修改private 的内容一般对外部的实现没有影响。
default/friendly/package 成员变量和成员方法可以被包中其他类访问,如果子类和父类不在同一个包中,子类不能访问父类缺省的成员变量和成员方法。如果是修饰的类,即类没有任何修饰符,则只能被同一个包内的所有类访问。一般用于修饰项目中一个包内部的功能类,这些类的功能只是辅助其它的类实现,而为包外部的类提供功能。
2、java向上转型为什么是安全,向下为什么是不安全?
原文地址 :http://blog.csdn.net/shanghui815/article/details/6088588 这个解释的很好,既能深入的理解继承和接口,还能明面转型的问题:
在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型。
向上转型
我们在现实中常常这样说:这个人会唱歌。在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”。再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类)。我们现实中也经常这样说:麻雀是鸟。这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类。这也符合Java提倡的面向抽象编程思想。来看下面的代码:
package a.b;
public class A {
public void a1() {
System.out.println("Superclass");
}
}
A的子类B:
package a.b;
public class B extends A {
public void a1() {
System.out.println("Childrenclass"); //覆盖父类方法
}
public void b1(){} //B类定义了自己的新方法
}
C类:
package a.b;
public class C {
public static void main(String[] args) {
A a = new B(); //向上转型
a.a1();
}
}
如果运行C,输出的是Superclass 还是Childrenclass?不是你原来预期的Superclass,而是Childrenclass。这是因为a实际上指向的是一个子类对象。当然,你不用担心,Java虚拟机会自动准确地识别出究竟该调用哪个具体的方法。不过,由于向上转型,a对象会遗失和父类不同的方法,例如b1()。有人可能会提出疑问:这不是多此一举吗?我们完全可以这样写:
B a = new B();
a.a1();
确实如此!但这样就丧失了面向抽象的编程特色,降低了可扩展性。其实,不仅仅如此,向上转型还可以减轻编程工作量。来看下面的显示器类Monitor:
package a.b;
public class Monitor{
public void displayText() {}
public void displayGraphics() {}
}
液晶显示器类LCDMonitor是Monitor的子类:
package a.b;
public class LCDMonitor extends Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
阴极射线管显示器类CRTMonitor自然也是Monitor的子类:
package a.b;
public class CRTMonitor extends Monitor {
public void displayText() {
System.out.println("CRT display text");
}
public void displayGraphics() {
System.out.println("CRT display graphics");
}
}
等离子显示器PlasmaMonitor也是Monitor的子类:
package a.b;
public class PlasmaMonitor extends Monitor {
public void displayText() {
System.out.println("Plasma display text");
}
public void displayGraphics() {
System.out.println("Plasma display graphics");
}
}
现在有一个MyMonitor类。假设没有向上转型,MyMonitor类代码如下:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor());
run(new CRTMonitor());
run(new PlasmaMonitor());
}
public static void run(LCDMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(CRTMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(PlasmaMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
}
可能你已经意识到上述代码有很多重复代码,而且也不易维护。有了向上转型,代码可以更为简洁:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor()); //向上转型
run(new CRTMonitor()); //向上转型
run(new PlasmaMonitor()); //向上转型
}
public static void run(Monitor monitor) { //父类实例作为参数
monitor.displayText();
monitor.displayGraphics();
}
}
我们也可以采用接口的方式,例如:
package a.b;
public interface Monitor {
abstract void displayText();
abstract void displayGraphics();
}
将液晶显示器类LCDMonitor稍作修改:
package a.b;
public class LCDMonitor implements Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
CRTMonitor、PlasmaMonitor类的修改方法与LCDMonitor类似,而MyMonitor可以不不作任何修改。
可以看出,向上转型体现了类的多态性,增强了程序的简洁性。
向下转型
子类转型成父类是向上转型,反过来说,父类转型成子类就是向下转型。但是,向下转型可能会带来一些问题:我们可以说麻雀是鸟,但不能说鸟就是麻雀。来看下面的例子:
A类:
package a.b;
public class A {
void aMthod() {
System.out.println("A method");
}
}
A的子类B:
package a.b;
public class B extends A {
void bMethod1() {
System.out.println("B method 1");
}
void bMethod2() {
System.out.println("B method 2");
}
}
C类:
package a.b;
public class C {
public static void main(String[] args) {
A a1 = new B(); // 向上转型
a1.aMthod(); // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2()
B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误
b1.aMthod(); // 调用父类A方法
b1.bMethod1(); // 调用B类方法
b1.bMethod2(); // 调用B类方法
A a2 = new A();
B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
}
从上面的代码我们可以得出这样一个结论:向下转型需要使用强制转换。运行C程序,控制台将输出:
Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at
a.b.C.main(C.java:14)
A method
A method
B method 1
B method 2
其实黑体部分的向下转型代码后的注释已经提示你将发生运行时错误。为什么前一句向下转型代码可以,而后一句代码却出错?这是因为a1指向一个子类B的对象,所以子类B的实例对象b1当然也可以指向a1。而a2是一个父类对象,子类对象b2不能指向父类对象a2。那么如何避免在执行向下转型时发生运行时ClassCastException异常?使用5.7.7节学过的instanceof就可以了。我们修改一下C类的代码:
A a2 = new A();
if (a2 instanceof B) {
B b2 = (B) a2;
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
这样处理后,就不用担心类型转换时发生ClassCastException异常了。
3、什么是别名机制?
原文地址:http://blog.csdn.net/killme2008/article/details/337744,讲的很详细。
用个简单的例子说明
public class Aliases{
int i;
public Aliases() { i=1; }
public Aliases(int i) { this.i=i; }
public static void main(String args[]) {
Aliases A=new Aliases();
Aliases B=A; //A和B指向了同一个对象,A和B互为别名
System.out.println("A.i and B.i:"+A.i+" "+B.i);
System.out.println("增加B:");
B.i++;
System.out.println(("A.i and B.i:"+A.i+" "+B.i); } }
输出:A.i and B.i:1 1
增加B:
A.i and B.i:2 2
很明显,A和B指向了同一个对象,B=A这个操作只是把A的引用复制给了B,而对象并未拷贝。java是通过Rerference来操作对象的,上面是一个显式别名的例子,当你往函数内传递对象时也会发生别名,如下:
public class Aliases{
int i;
public Aliases() { i=1; }
public Aliases(int i) { this.i=i; }
public Increment(Aliases AS) { AS.i++; }
public static void main(String args[]) {
Aliases A=new Aliases();
System.out.println("A.i before Increment:"+A.i);
Increment(A);
System.out.println("A.i after Increment:"+A.i);
}
}
你可以看到A在经过函数Increment()的调用后i的值发生了变化。在某种情况下,你可能不希望传入的对象发生变化,希望函数内的对象只是传入对象的副本,对这个副本的改变不至于影响原来的对象,那该如何处理?我们知道C++是通过把参数声明了const,就意味着此参数不可改变,但是别忘了,C++有所谓的拷贝构造函数,所以在函数中的对象确实是拷贝,而java并未支持拷贝构造函数,原因很明显,java传递对象的引用,你就算拷贝也只是引用的拷贝而已(所以有人说java本质上只有传值)。那么就没办法了吗?有的,那就是“克隆机制”,在根类Object已经定义了clone()方法,你所要做的只是实现cloneable接口,并覆写clone()方法,典型的应用如下
class CloneClass implements Cloneable{
public int aInt;
public Object clone(){
CloneClass o = null;
try{
o = (CloneClass)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
} return o;
}
}
调用super.clone()方法,它会为你自动处理存储分配和复制操作,从而实现了对象的深层拷贝。我们又知道,通过serilization也可以实现对象的深层拷贝啊,为什么不用这个?根本原因在于效率上的巨大差异,clone()虽然一开始好象很复杂,但毕竟没有对象的读写那么耗费资源。有了clone机制,你就可以在方法调用内部制造一个对象的副本了,它是局域性,对它的任何操作都不至于影响原对象的状态了。我个人认为,这点对于编写一个安全的大型程序是非常重要的。
对于以上问题,我理解比较模糊,所以通过万能的互联网查询相关解释,感谢上述链接的作者!
相关推荐
Think in java 读书笔记 java教程
王者归来之--Java编程思想读书笔记 Think in java4th
学习 Think In Java 之后的总结,一些学习笔记,提供学习
java 很好的java学习文档,是学习java的入门基础,谢谢你的下载
Think in java 源码构建编译
think in java 源码整理,应该算是比较全面的,有需要的朋友可以下下来看下
Think in java 的代码源码,里面很详细的习题详解
java think in java (英文第四版)至今为止 被认为是java教程之中权威作品之一
think in java 第四版 源码以及作业 eclipse版本 包含jar包 可以直接导入eclipse
Think Data Structures in Java 英文azw3 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
这是java编程思想中的练习题,自己感觉不错,上传上去给大家分享~~~~~
Think in Java 作者的文章 精辟见解
Think in java 教程 Think in java 教程
抽象的进步 1.2 对象的接口 1.3 实现方案的隐藏 1.4 方案的重复使用 1.5 继承:重新使用接口 1.5.1 改善基础类 1.5.2 等价和类似关系 1.6 多形对象的互换使用 1.6.1 动态绑定 ...1.11 Java和因特网
Think in Java(美)Bruce Eckel 著 陈昊鹏 译 引言 同人类任何语言一样,Java为我们提供了一种表达思想的方式。如操作得当,同其他方式相 比,随着问题变得愈大和愈复杂,这种表达方式的方便性和灵活性会显露无遗。 ...
Think In Enterprise Java v1.1
学习think in java 时的第9章的例题及练习答案。 eclipse 工程包,运行可用!全自己敲的!
编程思想第四版完整中文高清版(免费)TXT格式
从一程序员朋友手里tiang来的,看看对你有帮助
经典的think in java4,所有源码,帮你早日攻克java学习的堡垒!!!