Java基础面试题

来源:互联网 发布:word文档朗读软件 编辑:程序博客网 时间:2024/06/06 03:11

1、关于下面的程序,哪个选项的说法是正确的?

public class Test {    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        byte a = 3,b=2;          //1        byte c = a+b;            //2        System.out.println(c);            }}


A、编译通过,运行时打印出5
B、编译通过,运行时打印出23
C、编译不通过,在//2出有错误,因为此处f必须是一个byte类型的变量
D、编译不通过,在//1出有错误,不能这样定义变量
解析:java中涉及byte、short和char类型的运算操作首先会把这些值转换为int类型,然后对int类型值进行运算,最后得到int类型的结果。因此,如果把两个byte类型的值相加,最后会得到一个int类型的结果。如果需要得到byte类型结果,必须将这个int类型的结果显式转换为byte类型
把2处代码改为下面就正确了:byte c = (byte) (a+b);   //2

2、以下程序错误的是:

A、short s=1;s=s+1;              B、short s=1;s+=1;
解析:s+1为int,不能直接赋值给short,而B中是读取右s的地址+1

3、下面程序执行会出现错误吗?如果有错是什么错误?

public class PerttyTest {    public static void main(String[] args){        String i="123",s;        s=getStr(i);              System.out.println(s);    }        public String getStr(String s){        StringBuffer sb=new StringBuffer();        for(int i=s.length()-1;i>=0;i--){            sb.append(s.charAt(i));        }          return sb.toString();    }}


解析:main函数是个static函数,getStr不是静态函数,不能在main中调用,或者将getStr声明为static的函数,或者实例化一个PerttyTest类来调用

4、谈谈final、finally、finalize的区别。

(1)final修饰符(关键字)
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既声明为abstract,又被声明为final。
将变量或方法声明为final,可以保证它们在使用中不被改变。其初始化可以在两个地方:一是其定义处,也就是说在final变量定义时直接给其赋值;二是在构造函数中。这两个地方只能选其一。声明为final的方法同样只能使用,不能重写(overide)
(2)finally
在异常处理时提供finally块来执行任何清除操作。如果抛出一个异常,那么相匹配的catch子句就会执行,然后控制就会进入finally块。
(3)finalize
finalize是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。

5、当你去编译和运行下面的代码时,会发生下面哪种情况?

class ExBase{    abstract public void martley(){    }}public class MyEx extends ExBase{    public static void main(String argv[]){        DataInputStream fi =new DataInputStream(System.in);        try{            fi.readChar();        }catch(IOException e){            System.exit(0)        }        finallly{Sytemt.out.println("Doing finally");}    }}


A. 编译时错误
B. 程序运行的时候,等待一个键盘输入然后就跳出
C. 程序运行的时候,等待一个键盘输入,在屏幕上显示出“Doing finally”,然后跳出
D. 运行中立即跳出
解析:这是一道典型的误导人思维的题目。其实程序会产生的错误就想本地方法和抽象方法没有方法体一样。另外,abstract方法所在的类必须用abstract修饰。还需要注意一个问题,abstract类中却不一定有abstract方法。抽象类不能够生成对象,抽象类天生是被继承的。抽象类的抽象方法都只能用public、abstract修饰,接口的方法也是这样。

6、说明浅复制和深复制的区别?

⑴浅复制(浅克隆)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
⑵深复制(深克隆)
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
举例说明:
class ShallowCopy implements Cloneable{    private Date begin;    public Date getBegin() {        return begin;    }    public void setBegin(Date begin) {        this.begin = begin;    }    @Override    protected Object clone() throws CloneNotSupportedException {        // TODO Auto-generated method stub        return super.clone();    }}class DeepCopy implements Cloneable{    private Date begin;    public Date getBegin() {        return begin;    }    public void setBegin(Date begin) {        this.begin = begin;    }    @Override    protected Object clone() throws CloneNotSupportedException {        // TODO Auto-generated method stub        DeepCopy obj=null;        obj=(DeepCopy) super.clone();        obj.setBegin((Date) getBegin().clone());        return obj;    }


7、实现一个拷贝构造函数:

public class Test1 {public int i;public Test test;public Test1() {// TODO Auto-generated constructor stub}public Test1(Test1 t){i=t.i;test = new Test();test.i=t.test.i;}/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stub//A a = new B();Test1 t = new Test1();t.i=9;t.test=new Test();t.test.i=10;Test1 t1=new Test1(t);System.out.println(t1.i);System.out.println(t1.test.i);}}class Test{public int i;public Test(){}public Test(Test t){i=t.i;}}


8、Java中public,protected,private,default的区别?

public,protected,private是Java里用来定义成员的访问权限的,另外还有一种是“default”,也就是在成员前不加任何权限修饰符。
这四个修饰符的访问权限如下表:
-----------------------------------------------
                类内部     package内       子类         package外
public          允许         允许          允许         允许
protected       允许         允许          允许         不允许
default         允许         允许          不允许       不允许
private         允许         不允许        不允许       不允许
-----------------------------------------------
Java的访问控制是停留在编译层的,也就是它不会再class文件中留下任何的痕迹,只在编译的时候进行访问控制的检查。
其实,通过反射的手段,是可以访问任何包下任何类中的成员的,例如,访问类的私有成员也是可能的。

9、abstract class和interface有什么区别?

含有abstract修饰符的class即为抽象类,abstract类不能创建的实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final,类型通常省略不写。
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。

10、Java中equal和==的区别是什么?

首先看一段代码:
public class Test1{    public static void main(String args[]){            String a="1234";            String b="1234";            String c = new String("1234");            System.out.println(a==b);            System.out.println(a==c);            System.out.println(a.equals(c));    }}


结果:
true
false
true
首先应该先了解java中String new和直接赋值的区别。
第二个为false的原因在于a和c指向的是不同的对象。==运用在基本数据类型的时候,通过比较他们的实际的值来判定是否相等,而用于比较引用类型的时候,则是比较两个引用的地址是否相等,也就是是否指向同一个对象。通过new来创建的字符串单独生成一个对象,所以a和c指向的不是同一个对象。

equal()方法是java.lang.object的方法,也就是所有的Java类都会有的方法。它可以被程序员覆盖重写,通过自定义的方式来判定两个对象是否相等。对于字符串String类来说,他的equal方法用来比较字符串的字符序列是否 完全相等。

11、Java中char的取值范围?

Java中char采用Unicode编码格式,用两个字节来表示一个字符,一共16bit,它所能表示的最大值为2的16次方

12、Java中char能否存储汉字?

char是可以存储汉字的,每个中文字符都有对应的Unicode编码。

13、Java中Overload(重载)和Override(覆盖)的区别

重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型,不关心返回值类型。如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Overload。这是不行的,我们可以用反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果,例如,我们调用map.remove(key)方法时,虽然remove方法有返回值,但是我们通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
覆盖,是指在子类中对父类的某方法进行重新定义,其子类的该方法名以及参数位置和个数以及返回值均与父类相同,从而在调用子类的该方法时,不会执行父类的方法。如果在父类中以final定义的方法,在子类中无法重写,编译器会报错。被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

子类覆盖父类的方法时,不能够降低父类方法的可见性,即父类的public方法不能覆盖为private,解释:

void func(SuperClass sc) {    sc.foo();}SuperClass sc = new ChildClass();func(sc);

如果在这里子类把父类的foo方法降低了可见性为protected甚至private,在func()调用时,sc.foo()是不可见的,编译就会出错

14、以下代码的输出是什么?

public class Test1 {public Test1() {// TODO Auto-generated constructor stub}/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubA a = new B();System.out.println("----------------");B b = new B();}}class A{static{System.out.println("AAAAAAAAAAAAAA static");}public A() {//super();System.out.println("AAAAAAAAAAAAAA");// TODO Auto-generated constructor stub}}class B extends A{static{System.out.println("BBBBBBBBBBBBBBB static");}public B() {//super();System.out.println("BBBBBBBBBBBBBB");}}


结果:
AAAAAAAAAAAAAA static
BBBBBBBBBBBBBBB static
AAAAAAAAAAAAAA
BBBBBBBBBBBBBB
----------------
AAAAAAAAAAAAAA
BBBBBBBBBBBBBB
static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法

15、Java中的几种引用方式:强引用、软引用、弱引用、虚引用的区别?

在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。
但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因 为也许将来还会派用场。对于这样的可有可无的物品,一种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃 圾清除,还是无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
1) 强引用
平时我们编程的时候例如:Object object=new Object();那object就是一个强引用了。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
2) 软引用(SoftReference)
如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只 要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联 合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
3) 弱引用(WeakReference)
如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回 收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 
4) 虚引用(PhantomReference)

"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在 任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队 列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

16、String str1="abc" 和String str2=new String("abc")的区别?

Java虚拟机在执行这段代码时,遇到双引号操作符,它会自动创建一个String对象,该String对象所代表的值就是abc,然后再返回该对象的一个引用。
对应str1字符串来说,它的创建过程同上所述。在Java5.0及其以后的版本,在创建该对象之前,JVM会在String对象池中去搜索该字符串对象是否已经被创建,如果已经被创建,则直接返回一个引用,否则先创建再返回引用。
而str2字符串变量,它的创建过程就要多一个步骤。它会额外的创建一个新的String对象,也就是new关键字的作用,并且返回一个引用给str2 。

Java中有对象池的概念,Java虚拟机启动时候会实例化9个对象池,分别用来存储8中基本类型的包装类和String对象。对象池的存在是为了频繁的创建和销毁对象而影响系统性能。
str1是在对象池中取对象,str2方法直接生成新的对象。
任何情况下,只要new一个String对象都是创建了新的对象。
因此表达式str1==str2的结果是false的。

17、String不能被继承,String作为方法参数时是传值而不是传引用

18、Vector与ArrayList的区别?

Vector与ArrayList都是List的实现类,它们都代表链表形式的数据结构。Vector是线程安全的,因为它操作元素的方法都是同步方法,而ArrayList则不是。开发过程中应该根据需要进行选择,如果需要保证线程安全的地方则需要使用Vector,而不必要的时候则无需使用Vector,因为ArrayList效率会高一些。

19、HashMap和HashTable的区别?

对于Map接口来说,它有两种比较重要的实现类HashMap和HashTable,它们保存元素的时候都是无序的。
HashTable的方法是同步的,HashMap不同同步。所以在多线程场合要使用HashTable,这个区别就行Vector和ArrayList一样。
HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
HashTable有一个contains方法,功能和containsValue()一样。
HashTable使用Enumeration,HashMap使用Iterator。
HashTable中hash数组的初始化大小及其增长方式不同。

20、写一个复制文件的程序。

本题目主要考察的是面试者对FileInputStream和FileOutputStream的使用,本质上也就是先从一个文件读出数据,然后再往另外一个文件写入数据。
FileInputStream类中最主要的是read()方法,通过它把数据从流中读到内存里来。read()方法的参数为一个byte数组,有一点像缓存,也就是把数据先读到内存中暂存,然后再进行相关操作。
FileOutputStream是用于打开一个输出流的,这里就需要把byte数组中的数据写入到输入流中。

    public static void main(String args[]){            FileInputStream fin = null;            FileOutputStream fou = null;            try {                fin = new FileInputStream("read.txt");                fou = new FileOutputStream("write.txt");                byte[] buff = new byte[512];                int len;                while((len=fin.read(buff))>0){                    fou.write(null, 0, len);                }                fin.close();                fou.close();            } catch (FileNotFoundException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            } catch (IOException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }finally{                            }    }


21、如何使用随机存取文件RandomAccessFile类?

InputSteam和OutputStream都只能单方面的读和写文件的内容,如果有随机的读取和写入文件的内容的需要那又该怎么办呢?Java为开发者提供了一个RandomAccessFile类,它就是专门用来随机存取文件内容的。
RandomAccessFile类操作文件内容的时候,就好像操作一块内存区域一样,把字节用下标来进行定位,通过调用RandomAccessFile的API方法,把指针的指向进行移动,达到随机存取数据的目的。
用length()方法获取文件的内容长度。
用seek()方法随机的到达任何需要存取数据的地方。
调用read()方法获取当前位置的数据,用write()方法写入数据。
完成需要以后,调用close()关闭文件。

22、字节流的处理方式?

字节流是I/O中最原始的方式,因为计算机处理数据总是以一个byte为基本单位的,字节流就是每次读取的单位为byte。I/O流总是分为两端的,一端作为输出,一端作为输入,因此就可以把流分为输入流和输出流。Java中的基础字节输入流和输出流的类为:InputStream和Outputstream。通过它们可以再衍生出FileInputStream和FileOutputstream、ObjectInputStream和ObjectOutputstream、BufferInputstream和BufferOutputStream等。
字节流最大的特点就是每次的输出和输入都是一个字节。注意的操作对象就是byte数组,通过read()和write()方法把byte数组中的数据写入或读出。

23、字符流的处理方式?

针对文本文件,Java提出了字符流的概念,使用字符流来写入和读出字符数据。无需再使用字节流进行包装。
字符流是由字节流包装而来,它的输入和输出流类型包括StringReader和StringWriter、BufferReader和BufferWriter。对于前者,它们的使用方法与字节流类似,主要还是read()和write()方法,而后者除了基本的read()和write()以外,有一个功能是在读取文章类型的文本文件时经常需要的,那就是readLine()方法。
字符流对象的创建的时候,一般是需要提供一个输入或输出流的。例如,在创建BufferedReader或BufferedWriter对象的时候,需要提供一个InputStreamReader或InputStreamWriter对象,另外,对于特定字符格式的文本内容,还需要再创建InputStreamReader或InputStreamWriter对象的时候,提供字符格式类型作为构造方法的参数。

    public static void main(String args[]){            try {                InputStream is = new FileInputStream("a.txt");                InputStreamReader isr = new InputStreamReader(is, "GBK");                BufferedReader br = new BufferedReader(isr);                StringBuffer sb = new StringBuffer();                String str=null;                while((str=br.readLine())!=null){                        sb.append(str);                }                br.close();            } catch (FileNotFoundException e2) {                // TODO Auto-generated catch block                e2.printStackTrace();            }catch (UnsupportedEncodingException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }catch (IOException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }            }


24、Java中实现多线程的方法?

继承Thread类和实现Runable接口,其实Thread是实现了Runnable接口的,就是说,本质上线程类是需要试下Runnable接口,只是Thread还提供了一些额外的方法。
继承Thread类,重写父类run()方法,调用start()来启动线程。

new Thread(){public void run(){}}.start();

和Thread的run方法一样Runnable的run只是普通方法,Runnable没有start方法。Runnable是接口,thread是类,runnable只提供一个run方法,建议使用runnable实现Java多线程。可以使用Thread+Runnable来实现多线程,不管如何,最终都需要通过thread.start()来使线程处于可运行状态。

new Thread(new Runnable(){public voidrun(){}}).start();

Runnable和Thread的区别?
Runnable接口和Thread类都是用来创建线程类的,它们都需要实现run()方法,似乎没有什么区别,其实。它们还是有差别的。
Java的类是不允许多继承的,也就是只能继承自一个类,那么如果线程类继承了Thread以后,就不能再继承其他的类了。而Runnable接口就不会有这个问题,因为类是可以实现多个接口的,另外Thread提供了很多关于线程的方法,例如,获取线程Id,线程名,线程状态等。对于比较复杂一点的线程,可能就需要run()方法中调用这些方法,而Runnable接口使用起来就没那么方便。

25、如何启动一个线程?

继承自Thread类的线程类,可以通过new关键字创建一个线程对象以后,执行start()方法开始一个线程。而实现了Runnable接口的线程类,需要用它的对象实例,作为Thread类构造方法的参数,创建一个Thread对象,然后调用start()方法开始一个线程。

26、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。例如,对于如下语句:
final StringBuffer a=new StringBuffer("immutable"); 执行如下语句将报告编译期错误:
a=new StringBuffer(""); 但是,执行如下语句则可以通过编译:
a.append(" broken!");
有人在定义方法的参数时,可能想采用如下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){
}
实际上,这是办不到的,在该方法内部仍然可以增加如下代码来修改参数对象:
param.append("a");

27、构造函数Constructor是否可被override?

构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。

其实你只需要记住一句话:构造器不是方法,那么用来修饰方法特性的所有修饰符都不能用来修饰构造器(并不等与构造器具备这些特性,虽然不能用static修饰构造器,但它却有静态特性)构造器只能用 public private protected这三个权限修饰符,且不能有返回语句。

子类的构造函数可以通过super关键字显式调用父类中的构造函数。如果子类中的构造函数没有显式调用父类中的构造函数,编译器就会自动在子类的构造函数中调用父类中参数为空的构造函数。

28、接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?抽象类中是否可以有静态的main方法?

接口可以继承接口。抽象类可以实现(implements)接口,抽象类可以继承具体类。抽象类中可以有静态的main方法。
备注:只要明白了接口和抽象类的本质和作用,这些问题都很好回答,你想想,如果你是java语言的设计者,你是否会提供这样的支持,如果不提供的话,有什么理由吗?如果你没有道理不提供,那答案就是肯定的了。
只有记住抽象类与普通类的唯一区别:就是不能创建实例对象和允许有abstract方法。

29、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

abstract的method不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与abstract混用。
关于synchronized与abstract合用的问题,我觉得也不行,我觉得synchronized应该是作用在一个具体的方法上才有意义。而且,方法上的synchronized同步所使用的同步锁对象是this,而抽象方法上无法确定this是什么。

30、内部类,静态内部类和匿名内部类的区别?

内部类:在一个类中定义的类,内部类中不能定义静态成员(静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已,这么一点小事,你还要把它放到类内部的一个类中,过分了啊!提供内部类,不是为让你干这种事情,无聊,不让你干。我想可能是既然静态成员类似c语言的全局变量,而内部类通常是用于创建内部对象用的,所以,把“全局变量”放在内部类中就是毫无意义的事情,既然是毫无意义的事情,就应该被禁止)。内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中。
在方法体外面定义的内部类的访问类型可以是public,protecte,默认的,private等4种类型,这就好像类中定义的成员变量有4种访问类型一样,它们决定这个内部类的定义对其他类是否可见;对于这种情况,我们也可以在外面创建内部类的实例对象,创建内部类的实例对象时,一定要先创建外部类的实例对象,然后用这个外部类的实例对象去创建内部类的实例对象,代码如下:
Outer outer = new Outer();
Outer.Inner1 inner1 = outer.new Innner1();
在方法内部定义的内部类前面不能有访问类型修饰符,就好像方法中定义的局部变量一样,但这种内部类的前面可以使用final或abstract修饰符。这种内部类对其他类是不可见的其他类无法引用这种内部类,但是这种内部类创建的实例对象可以传递给其他类访问。这种内部类必须是先定义,后使用,即内部类的定义代码必须出现在使用该类之前,这与方法中的局部变量必须先定义后使用的道理也是一样的。这种内部类可以访问方法体中的局部变量,但是,该局部变量前必须加final修饰符。
静态内部类:它不再具有内部类的特性,所有,从狭义上讲,它不是内部类。可以有静态的方法。与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差别,它可以定义成public、protected、默认的、private等多种类型,而普通类只能定义成public和默认的这两种类型。在外面引用Static Nested Class类的名称为“外部类名.内部类名”。在外面不需要创建外部类的实例对象,就可以直接创建Static Nested Class,例如,假设Inner是定义在Outer类中的Static Nested Class,那么可以使用如下语句创建Inner类:
Outer.Inner inner = newOuter.Inner();
匿名内部类:匿名的内部类是没有名字的内部类,是继承其他类或实现其他接口的一个实例。
匿名内部类不能有构造方法。不能定义任何静态成员、方法和类。 内部类不能是public,protected,private,static。只能创建匿名内部类的一个实例。 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

31、以下代码的执行结果是什么?

public class Test1{    public static void main(String args[]){        Test1 t = new Test1();        int b = t.get();        System.out.println(b);                }    public int get(){        try {            System.out.println("1111111111");            return 1;                    } catch (Exception e) {            // TODO: handle exception        }finally{            System.out.println("222222222222");            return 2;        }    }}


1111111111
222222222222
2

32、wait(), notify(),nofityAll(),sleep()的区别

在JAVA中,是没有类似于PV操作、进程互斥等相关的方法的。JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。明白这个原理,就能理解为什么synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。如果只是简单的想要实现在JAVA中的线程互斥,明白这些基本就已经够了。但如果需要在线程间相互唤醒的话就需要借助Object.wait(), Object.nofity()了。
Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait就是说线程正拥有对象锁,此时主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的锁。相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
这里要注意一点:notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor。
举个简单的例子:假如有三个线程Thread1、Thread2和Thread3都在等待对象objectA的monitor,此时Thread4拥有对象objectA的monitor,当在Thread4中调用objectA.notify()方法之后,Thread1、Thread2和Thread3只有一个能被唤醒。注意,被唤醒不等于立刻就获取了objectA的monitor。假若在Thread4中调用objectA.notifyAll()方法,则Thread1、Thread2和Thread3三个线程都会被唤醒,至于哪个线程接下来能够获取到objectA的monitor就具体依赖于操作系统的调度了。
上面尤其要注意一点,一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块,释放对象锁后,其余线程才可获得锁执行。

33、Java中Collection和Collections的区别?

Collection是集合类的一个顶级接口,其直接继承接口有List与Set
而Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

34、String s = new String("xyz");创建了几个String Object?二者之间有什么区别?

两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新String对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。

35、以下代码的打印结果是什么?

public class TestJava {public static boolean foo(char c){System.out.print(c);return true;}public static void main(String[] arg0){int i=0;for(foo('A');foo('B')&&i<2;foo('C')){i++;foo('D');}}}

ABDCBDCB

36、java中stack和heap的区别

基本类型、对象的引用储存在stack中;对象储存在heap中。

37、下面哪个选项会生成一个内部类的实例?

public class TestJava {        public void testFunc(){        //Line 4    }    public static void main(String[] arg0){        TestJava t = new TestJava();        //Line 9    }        public class Inner{}}


A    new Inner();           //Line 4
B    new Inner();           //Line 9
C    new t.Inner();         //Line 9
C    new TestJava.Inner();  //Line 9
E    t.new Inner();         //Line 9

答案:

E

3 0
原创粉丝点击