java基础知识学习

  1. 一个"java"源文件中是否可可以包含多个类?有什么限制?

    可以有多个类,但是只能有一个public的类,并且public的类必须和文件名相一致
  2. java中有没有"goto"?

    java中的保留字,但是现在没有在java中使用
  3. &和&&区别

     1. 都可以作为逻辑运算符,表示逻辑与(and),当运算符两边的表达式的结果为true时,结果才为true,否则为false
    
    1. &&具有短路功能,当第一个表达式为false时,则不会在计算第二个表达式
    2. &还可以作为位运算符,当&表达式两边的不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位
      4. 在java中如何跳出当前的多重嵌套循环?
      在java中想要跳出多重循环,可以在外面定义一个标号,然后在里面循环体的代码中使用带有标号的break语句,即可跳出外层循环,例如
 ok;
	 for (int i = 0;i<10;i++) {
 		for (int j = 0;j<10;j++) {
 			if (j==5)break ok;
				}
 			}
		

break,continue,return之间的区别和联系
1. break
1. 结束当前整个循环,执行当前循环下面的语句.
2. 只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出
3. break在循环体内,强行结束循环的执行,也就是结束整个循环过程,不再判断执行循环的条件是否成立,直接转向循环语句下面的语句
4. 当break出现在循环体中的是switch语句体内,其作用只是跳出该switch语句体
总的来说:就近原则,结束当前整个循环
2. return
1. 从当前的方法中退出,返回到该调用的方法的语句处,继续执行
2. 返回一个值给调用该方法的语句,返回值的数据类型必须和方法的声明中的返回值类型一致
3. 后面不带参数,返回空,其实就是想中断函数的执行,返回调用函数处
3. continue
1. 终止本次循环的执行,即跳过当前这次循环中continue语句后尚未执行的语句 ,接着进行下一次循环条件的判断
2. 结束当前循环,进行下一次循环判断
3. 只能终止循环中的一次过程,但不能终止循环继续进行
5. 局部变量和成员变量的区别?
1. 在类中的位置不同
成员变量:在类中方法外
局部变量:在方法或代码块中,或者方法的声明上(即在参数列表中)
2. 在内存中的位置不同
成员变量:在堆中
局部变量:在栈中
3. 生命周期不同
成员变量:随着对象的创建而存在,随着对形象的消失而消失
局部变量:随着方法的调用或者代码块的执行而存在,随着方法的调用完成或代码块的执行完毕而消失
4. 初始值
成员变量:有初始默认值
局部变量:没有初始默认值,使用之前需要赋值

public class VariableDemo {
String name = "成员变量";

 public static void main(String[] args) {
     new VariableDemo().show();
 }

 public void show() {
     String name = "局部变量";
     System.out.println(name);
 }
}</code></pre>

访问成员变量:
<pre><code>public class VariableDemo {
 String name = "成员变量";

 public static void main(String[] args) {
     new VariableDemo().show();
 }

 public void show() {
     String name = "局部变量";
     System.out.println(this.name);
 }
}</code></pre>
  1. java中this关键字的作用

    1. this关键字主要的三个应用
      1. 调用本类中的属性也就是类中的成员变量
      2. 调用本类中的其他方法
      3. 调用本类中的其他构造方法,调用时要房子构造方法的首行
        public class Student{
         String name;//定义一个成员变量
         private void SetName(String name)//定义一个局部变量 name
         this.name = name; }
    2. 在方法内部,如果成员变量和局部变量同名的话,以局部变量为准(就近原则)
    3. 调用 类的构造方法
      public class Student { //定义一个类,类的名字为student。 
      

    public Student() { //定义一个方法,名字与类相同故为构造方法
    this(“Hello!”);
    }
    public Student(String name) { //定义一个带形式参数的构造方法
    }
    }


构造方法是一个与类同名的方法,如果类中没有显示的写出构造方法,则在编译的时候会在动添加一个没有参数的构造方法

  • switch语句能否作用在byte上,能否作用在long上,能否作用在String上?

    
     在switch中,expr1只能是一整个表达式或者枚举常量,整数表达式可以是int基本类型或Integer包装类型,由于Byte,short,char都可以隐含转为int,所以这些类型以及这些类型的包装类也是可以的.显然long和string类型都不符合switch的语法规定,并且不能被隐式转换为int类型,所以他们不能用语switch语句
     
  • short s1 = 1;s1 = s1 + 1;有什么错?short s1 = 1;s1+= 1;有什么错?

    
     对于short s1 = 1;s1 = s1 + 1;由于s1 + 1运算时会自动提升表达式类型,所以结果是int型,在赋值给short类型s1时,会报告强制类型转换错误
     对于short s1 = 1; s1 += 1;由于 += 是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
     
  • char型变量中能不能存贮一个中文汉字?why?
    char类型的变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字,但是如果有的汉字没有包含在unicode编码中,就不能存储了,unicode编码占用两个字节,char类型的变量也是占用两个字节

  • 用最有效的方法算出2乘以8等于几?
    2 << 3,
    因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2 << 3

  • sql语句的执行顺序

    1. from
    2. where
    3. group by
    4. having
    5. select
    6. distinct
    7. union
    8. order by
  • 使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
    final修饰一个变量的时候,是指引用变量不能变,引用变量所指向的对象中的内容还是可以变的

  • "=="和equals方法区别?

    1. 是用来比较两个变量的值是否相等,也就是用来比较变量所对应的内存中所存储的数值是否相等,要比较两个基本类型的数据或者两个引用变量是相等,只能用操作符
      如果一个变量指向的变量是对象类型的,那这时设计到两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,此时变量所对应的内存中存储的数值就是对象占用的那块内存的首地址,对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,就是要看两个变量所对应的内存中数值是否相等,这时候就用到==操作符进行比较
    2. equals方法是用于比较两个独立对象的内容是否相同
    如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:
    boolean equals(Object o){
    return this==o;
    }
    这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的.
  • 静态变量和实例变量的区别

    1. 语法上的区别
      静态变量前要加是static关键字,而实例变量则不加
    2. 程序运行上的区别
      实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量,静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,就可以被使用了,总之实例实例变量必须创建对象后才可以被使用,静态变量则可以通过类名来引用
  • 是否可以从一个static方法内部发出对非static方法的调用?

    不可以.因为非静态方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法的调用,而静态方法调用是不需要创建对象,可以直接调用,所以当一个静态方法被调用时可能还没有创建任何实例对象
  • Integer和int的区别
    Integer是java为int提供的封装类,int的默认值是0,而Integer的默认值是null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出来

  • 四种访问修饰符的区别
    访问权限 类 包 子类 其他包

    public ∨ ∨ ∨ ∨

    protect ∨ ∨ ∨ ×

    default ∨ ∨ × ×

    private ∨ × × ×
    注意当重写父类的成员变量时,子类的成员变量不能比父类的成员变量的访问权限小,一般重写把权限定义相同即可
    default 权限问题
    不写默认default同public一样可以修饰任何类而且类名要与文件名相同

  • overloaded 和 override 的区别.
    overloaded是重载的意思,override是覆盖的意思,也就是重写
    overloaded表示同一个类中可以有多个名称相同的方法,但是参数列表各不相同
    override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中定义的方法,相当于把父类中的那个方法给完全覆盖了,
    子类覆盖父类的时候
    只能比父类抛出更少的异常,因为子类可以解决父类的一些问题,但是不能比父类有更多的问题
    访问权限
    子类的访问权限只能比父类的更大,不能比父类的小,如果父类的方法是private,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法

  • java中实现多态的机制是什么?
    靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法

  • abstract的method是否可以同时是static,是否可同时是native,是否可同时是synchronized?
    abstract的method不能会死static,因为抽象的方法要被子类实现的,而static与子类扯不上关系
    native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在被子类实现的问题,所以他也不能是抽象的

  • string和stringBuffer的区别?
    他们可以储存和操作字符串,string类提供了数值不可变的字符串,而stringbuffer长度是可变的string实现了equals和hashcode方法,而stringbuffer没有实现

  • 数组有没有length()这个方法?String有没有length()这个方法?
    数组没有length()这个方法,有length()属性,string有length()这个方法

  • final,finally,finalize的区别
    final用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承
    内部类要访问局部变量,局部变量必须定义成final的
    finally 是异常处理语句结构的一部分,表示总是执行
    finally 是object的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收

  • error和exception区别?
    error 表示恢复不是不可能但是很困难的情况下的一种严重问题
    exception表示一种设计或者实现问题,也就是说如果程序运行正常,不会发生这种错误

  • java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和 suspend()方法为何不推荐使 用?
    有两种方法实现,分别是继承thread类和实现runnable接口
    使用synchronized关键字来修饰同步方法
    反对使用stop(),因为他是不安全的,他会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改他们,结果很难检查出真正的问题.suspend()容易放生死锁,调用的时候,目标线程会停下来,但却仍然持有在这之前的锁定.此时.其他任何线程都不能访问锁定的资源,除非被挂起的线程恢复运行,对任何线程来说,如果他们想恢复目标线程,同时又视图试用一个锁定的资源,就会造成死锁,所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起,若标志指出线程应该挂起,使用wait()命令使其进入等待状态,若标志指出线程应该恢复,则用一个notify()重新启动线程

  • sleep()和wait()区别?
    sleep()就是让正在执行的线程,主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入同步锁,sleep方法并不会释放锁,即使当前线程时候用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行.wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待同步锁的线程可以得到同步锁并继续运行,只有其他线程调用了notify()方法(notify()并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放.),调用wait方法的线程就会接触wait状态和程序可以再次得到锁后继续向下执行

  • 多线程有几种实现方式?同步有几种实现方式?
    多线程:继承thread类或者实现runnable接口
    同步的实现方面有两种,分别时synchronized,wait与notify
    wait():使一个线程处于等待状态,并且释放所持有的对象的lock
    sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedEvcption异常
    notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而不是按优先级.
    Allnotify():唤醒所有处于等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让他们竞争

  • 启动一个线程是run()还是start()?
    启动一个线程是调用start()使线程处于就绪状态,以后可以被调度为运行状体,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码

  • 当一个线程进入一个对象的synchronized方法后,其他线程是否可进入此对象的其他方法?
    分几种情况:

    1. 其他方法前是否加了sysnchronized关键字,如果没加,则能
    2. 如果这个放法内部调用了wait,则可以进入其他sysnchronized方法
    3. 如果其他方法都加了sysnchronized关键字,并且内部没有调用wait,则不能
    4. 如果其他方法是static,他用的同步锁是当前类的字节码,而非静态的方法不能同步,因为非静态的方法用的是this
  • 线程的基本概念,线程的基本状态以及状态之间的关系
    一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段代码同时执行,每个程序至少有一个线程,即main方法执行的那个线程.如果一个cpu,他怎么同时执行多段程序呢?这是从宏观上来看的cpu一会执行a线索,一会执行b线索,切换时间很快,给人的感觉就是在同时执行

    状态:就绪,运行,sysnchronize阻塞,wait和sleep挂起,结束.wait必须在sysnchronized内部调用
    调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到sysnchronized语句时,由运行状态转为阻塞,当sysnchronized获得锁后,由阻塞转为运行,在这种状态下可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态.

  • 简述sysnchronized和java.util.concurrent.locks.lock的异同?
    相同点:Lock能完成sysnchronized所实现的所有功能
    不同点:Lock有比sysnchronized更精确的线程语义和更好的性能.sysnchronized会自动释放锁,而Lock一定要求程序员手动释放,并且必须在finally从句中释放.Lock还有更强大的方法,他的tryLock方法可以非阻塞方式去拿锁

    
    	 public class ThreadTest{
    private int j;
    private Lock lock = new ReentrantLock();
    public static void main(String[] args) {
    	
    	ThreadTest tt = new ThreadTest();
    	for(int i=0;i<2;i++)
    	{
    		new Thread(tt.new Adder()).start();
    		new Thread(tt.new Subtractor()).start();
    	}
    }
    

    private class Subtractor implements Runnable{
    public void run(){
    while(true){
    lock.lock();
    try{
    System.out.println(j--);
    }finally{
    lock.unlock();
    }
    }
    }
    }

    private class Adder implements Runnable{
    public void run(){
    while(true){
    lock.lock();
    try{
    System.out.println(j--);
    }finally{
    lock.unlock();
    }
    }
    }
    }
    }

  • collection框架中实现比较要实现什么接口?
    comparable

  • ArrayList和Vector的区别?
    这两个类都实现了List接口,他们都是有序的集合,相当与一种动态的数组,其中的元素是允许重复的,这是HashSet之类的集合的最大不同处,HashSet集合不可以按索引去检索其中的元素
    区别:

    1. 同步性: Vactor是线程安全的,也就是说他的方法之间是线程同步的,而ArrayList是线程不安全的,它的方法之间是线程不同步的.如果只有一个线程会访问到集合,那最好是ArraryList,因为它不考虑线程安全的问题,效率会高一些;如果有多个线程会访问到集合,那最好使用Vector,因为不需要我们自己去再考虑和编写线程安全的代码
    2. 数据增长: ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。
      总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。
  • HashMap和HashTable的区别:
    主要区别在于HashMap允许空值,由于线程安全,在只有一个 线程访问的情况下,效率要高于HashTable
    HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
    最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
    Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。

    就HashMap与HashTable主要从三方面来说。
    一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
    二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
    三.值:只有HashMap可以让你将空值作为一个表的条目的key或value

  • List,Set,Map是否继承Collection接口?
    List,Set是,Map不是

  • Collection和Collections的区别?
    Collection是集合类的上级接口,继承与他的接口主要有Set和List
    Collections是针对于集合类的一个帮助父类,他提供一系列静态方法实现对集合的搜索,排序,线程安全化等操作

  • 如果Tree里放对象,如果同时放入了父类和子类的实例对象,那比较时是使用父类的 compareTo方法还是使用子类的,还是抛异常?
    当add方法放入的是哪个对象,就调用哪个对象的compareTo方法,至于这个compareTo方法怎么做,就看当前这个对象的类是如何编写这个方法的

  • 字节流和字符流的区别
    底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转换成字节再进行底层写入,字符流是字节流的包装,字符流直接接受字符串,它内部将串转成字节,再存入底层设备
    字符想字节转换时,要注意编码的问题,因为字符串是转换成字节数组

  • 什么是java的序列化,如何实现java序列化?或者解释serializeable接口的作用
    我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java帮我们做,要被传输的对象,要被传输的对象必须实现seriablizable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化,需要被序列化的类必须实现Seriableble接口,该接口是一个mini接口,其实没有需要实现的方法,implements Seriablizable只是为了标注该对象是可被序列化的
    例如:在web开发中,如果一个对象被保存在了Session中,tomcat在重启时要把session对象序列化到硬盘上,这个对象就必须实现seriablizable接口,如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Seriablizable接口

  • 描述一下JVM加载class文件的原理和机制
    JVM中类的装载是由ClassLoaderde和他的子类来实现的,java ClassLoader 是一个重要的java运行时系统组件,它负责在运行时查找和装入类文件的类

  • GC是什么?为什么要有GC?
    GC是垃圾收集的意思,内存处理是编程人员很容易出现问题的地方,java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,java语言没有提供释放自己内存的显示操作方法

  • 垃圾回收的优点和原理
    java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域",垃圾回收可以防止内存泄漏,有效的使用可以使用的内存,垃圾回收器通常作为一个单独的低级别的线程运行,不可预知的情况下内存堆中已经死亡或者长时间没有使用的对象进行回收,程序员并不能调用垃圾回收器对某个对象所有对象进行垃圾回收,回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收

  • 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?什么办法主动通知虚拟机进行垃圾回收?
    对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址,大小,以及使用情况.通常GC采用有向图的方式记录 和管理堆中的所有对象,确定哪些对象是"可达的",那些是"不可达的".当GC确定哪些对象是不可达的,GC就有责任回收这些内存空间.
    程序员也可以手动执行Ststem.gc(),通知GC运行,但是java语言规范并不保证GC一定会执行

  • java中会存在内存泄漏吗,请简单描述?
    所谓内存泄漏就是指一个不再被程序使用的对象或变量一直被占据在内存中.java中有垃圾回收机制,它可以保证一个对象不再被引用的时候,对象将自动被垃圾回收器从内存中清除掉.由于java使用有向图的方式进行垃圾回收管理.可以消除引用循环的问题,例如两个对象互相引用着,只要他们的根进程不可达,那么GC可是可以回收他们的
    java中的内存泄漏情况,长生命周期的对象持有短声明周期的引用就可能引发内存泄漏,

  • 能不能自己写一个类,java.lang.String?
    可以,但是在引用的时候需要用自己的类加载器去加载,否则系统的加载器永远只加载jre.jar包中的那个java.lang.String.由于在tomcat的web应用程序中,都是有webapp自己的类加载器先 加载WEB-INF/classes目录中的类,然后才委托上级的类加载器加载,如果我们在tomcat的web应用程序中写一个java.lang.String,但是会出现一个问题,原来用个java.lang.String的类都将出现问题
    虽然java提供了endoresed技术,可以覆盖jdk中的某些类,但是能够覆盖的是有限的,反正不包括java.lang这样的包中的类
    jre自带的java.lang.String,而该类中没有main方法

  • 代码查错

    
    1.
    
  • abstract class Name {
    private String name;
    public abstract boolean isStupidName(String name) {}
    }
    大侠们,这有何错误?
    答案: 错。abstract method必须以分号结尾,且不带花括号。
    2.
    public class Something {
    void doSomething () {
    private String s = "";
    int l = s.length();
    }
    }
    有错吗?
    答案: 错。局部变量前不能放置任何访问修饰符 (private,public,和protected)。final可以用来修饰局部变量
    (final如同abstract和strictfp,都是非访问修饰符,strictfp只能修饰class和method而非variable)。
    3.
    abstract class Something {
    private abstract String doSomething ();
    }
    这好像没什么错吧?
    答案: 错。abstract的methods不能以private修饰。abstract的methods就是让子类implement(实现)具体细节的,怎么可以用private把abstract
    method封锁起来呢? (同理,abstract method前不能加final)。
    4.
    public class Something {
    public int addOne(final int x) {
    return ++x;
    }
    }
    这个比较明显。
    答案: 错。int x被修饰成final,意味着x不能在addOne method中被修改。
    5.
    public class Something {
    public static void main(String[] args) {
    Other o = new Other();
    new Something().addOne(o);
    }
    public void addOne(final Other o) {
    o.i++;
    }
    }
    class Other {
    public int i;
    }
    和上面的很相似,都是关于final的问题,这有错吗?
    答案: 正确。在addOne method中,参数o被修饰成final。如果在addOne method里我们修改了o的reference
    (比如: o = new Other()😉,那么如同上例这题也是错的。但这里修改的是o的member vairable
    (成员变量),而o的reference并没有改变。
    6.
    class Something {
    int i;
    public void doSomething() {
    System.out.println("i = " + i);
    }
    }
    有什么错呢? 看不出来啊。
    答案: 正确。输出的是"i = 0"。int i属於instant variable (实例变量,或叫成员变量)。instant variable有default value。int的default value是0。
    7.
    class Something {
    final int i;
    public void doSomething() {
    System.out.println("i = " + i);
    }
    }
    和上面一题只有一个地方不同,就是多了一个final。这难道就错了吗?
    答案: 错。final int i是个final的instant variable (实例变量,或叫成员变量)。final的instant variable没有default value,必须在constructor (构造器)结束之前被赋予一个明确的值。可以修改为"final int i = 0;"。
    8.
    public class Something {
    public static void main(String[] args) {
    Something s = new Something();
    System.out.println("s.doSomething() returns " + doSomething());
    }
    public String doSomething() {
    return "Do something ...";
    }
    }
    看上去很完美。
    答案: 错。看上去在main里call doSomething没有什么问题,毕竟两个methods都在同一个class里。但仔细看,main是static的。static method不能直接call non-static methods。可改成"System.out.println("s.doSomething() returns " + s.doSomething());"。同理,static method不能访问non-static instant variable。
    9.
    此处,Something类的文件名叫OtherThing.java
    class Something {
    private static void main(String[] something_to_do) {
    System.out.println("Do something ...");
    }
    }
    这个好像很明显。
    答案: 正确。从来没有人说过Java的Class名字必须和其文件名相同。但public class的名字必须和文件名相同。
    10.
    interface A{
    int x = 0;
    }
    class B{
    int x =1;
    }
    class C extends B implements A {
    public void pX(){
    System.out.println(x);
    }
    public static void main(String[] args) {
    new C().pX();
    }
    }
    答案:错误。在编译时会发生错误(错误描述不同的JVM有不同的信息,意思就是未明确的x调用,两个x都匹配(就象在同时import java.util和java.sql两个包时直接声明Date一样)。对于父类的变量,可以用super.x来明确,而接口的属性默认隐含为 public static final.所以可以通过A.x来明确。
    11.
    interface Playable {
    void play();
    }
    interface Bounceable {
    void play();
    }
    interface Rollable extends Playable, Bounceable {
    Ball ball = new Ball("PingPang");
    }
    class Ball implements Rollable {
    private String name;
    public String getName() {
    return name;
    }
    public Ball(String name) {
    this.name = name;
    }
    public void play() {
    ball = new Ball("Football");
    System.out.println(ball.getName());
    }
    }
    这个错误不容易发现。
    答案: 错。"interface Rollable extends Playable, Bounceable"没有问题。interface可继承多个interfaces,所以这里没错。问题出在interface Rollable里的"Ball ball = new Ball("PingPang");"。任何在interface里声明的interface variable (接口变量,也可称成员变量),默认为public static final。也就是说"Ball ball = new Ball("PingPang");"实际上是"public static final Ball ball = new Ball("PingPang");"。在Ball类的Play()方法中,"ball = new Ball("Football");"改变了ball的reference,而这里的ball来自Rollable interface,Rollable interface里的ball是public static final的,final的object是不能被改变reference的。因此编译器将在"ball = new Ball("Football");"这里显示有错。

    posted @ 2017-08-24 14:47  大魚`海棠  阅读(197)  评论(0编辑  收藏  举报