标签:消失 面试题 竞争 开发 不可变 操作 单线程 布尔 索引
1. 重载与重写的区别:
答:(1).重写必须继承,重载不用。
(2).重写的方法名,参数数目相同,参数类型兼容,重载的方法名相同,参数列表不同。
(3).重写的方法修饰符大于等于父类的方法,重载和修饰符无关。
(public>protected>default>private)
(4).重写不可以抛出父类没有抛出的一般异常,可以抛出运行时异常
(5) 被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
(6) 静态方法不能被重写为非静态的方法(会编译出错)。
(7) 方法的异常类型和数目不会对重载造成影响;
(8) 不能通过访问权限、返回类型、抛出的异常进行重载;
2. 抽象类与接口的比较
答:(1). 抽象类的成员可以具有访问级别,而接口的成员全部public级别
抽象类:abstract 接口:interface 只能用public修饰
(2). 抽象类可以包含字段,而接口不可以,
(3). 抽象类可以继承接口,而接口不能继承抽象类
(4). 抽象类的成员可以具有具体实现的方法,而接口不行
(5). 抽象的子类可以选择性实现其基类的抽象方法,而接口的子类必须实现
(6). 抽象类是多个子类的共同模板,接口是一种规范
(7). 类是单继承的,接口是多继承的。
(8). 接口没有构造器、普通方法,抽象类有构造器、普通方法
3. 抽象类和非抽象类的不同点
答: public abstract class A{}
public class class B{}
(1). 抽象类声明时要使用abstract关键字来定义,而普通类可以是public , private 等;
(2)、抽象类里的抽象方法不能有方法的主体, 只能是方法的声明,例如 abstract void AMetho,而普通类的方法可以有主体。
抽象方法:public abstract String getType(); 抽象方法
普通方法:public string getType(){
return null;
}
(3)、抽象类被继承时、子类必须实现它的所有方法,而普通类不需要;
(4)、抽象类的方法在扩展性和延伸性方面要比普通类的好;
(5)、抽象类不能被实例化
(6)、抽象类不能用final修饰
(7)、static和abstract不能共存?
4.链表的优点
答:如linkedlist,链表的好处是删除快,但是在增添的时候速度慢, arraylist是普通数组,在删除时要移位,数量级大的情况下速度非常慢。
5.循环有哪几种形式
答:(1):while循环:
while(条件)
{循环体}
先判断条件 满足就执行循环,不满足就跳出循环
(2):do...while循环:
do{循环体}
while(条件)
先执行循环体,在判断条件
(3):for循环:
for(初始化变量;条件;迭代语句)
{循环体}
判断条件->执行循环体->执行迭代语句->判断
(4):foreach循环:
for(元素类型的变量:数组或集合){}
把数组或集合里面的元素循环遍历出来 不能改变值
6.Person person=new Person();执行的步骤
答:(1):分配空间 在堆内存中给new Vehicle这个刚创建的对象分配一个内存空间
(2):初始化 末尾的()意味着,在对象创建后,立即调用Vehicle类的构造函数,对刚生成的对象进行初始化。构造函数是肯定 有的。如果没创建,Java会补上一个默认的构造函数。
(3):Person person 创建一个Person 类的引用对象
(4):指向 ‘=’操作符使对象的引用指向刚创建的对象
7.8大基本类型以及其对应的封装类
答: 数据类型:byte====封装类:Byte 初始值:(byte)0 占用字节数:1 取值范围:-128~127
数据类型:short===封装类:short 初始值:(short)0 占用字节数:2 取值范围:-32768~32767
数据类型:int=====封装类:Integer 初始值:0 占用字节数:4 取值范围:-2147483648~2147483647
数据类型:long====封装类:Long 初始值:0L 占用字节数:8 取值范围:-9223372036854775808~922337236854775807
数据类型:float===封装类:Folat 初始值:0.0f 占用字节数:4 取值范围:1.4013E-45~3.4028E+38
数据类型:double==封装类:Double 初始值:0.0d 占用字节数:8 取值范围:4.9E-324~1.7977E+308
数据类型:char====封装类:Characte 初始值:\u0000 占用字节数:2 取值范围:0~65536
数据类型:boolean=封装类:Boolean 初始值:false 占用字节数:1 取值范围:true/false
8.final的作用
答:用final修饰的属性,方法,类。不能被赋值 重写 继承
9.构造器Constructor是否可被override
答:构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
10.子类继承父类的特点。
答:子类将拥有父类所有的非私有的方法和属性,子类还可以拥有自己独有的方法和属性,
声明父类,实例化子类时,子类会自动向上转型为父类
(1)、方法名称一致
(2)、参数一致
(3)、返回值一致
(4)、方法的权限不能比父类的小
(5)、不能比父类抛出更多的异常
11.throw throws的区别
答:public Test() throws RepletException {
try {
System.out.println("Test this Project!")
}catch (Exception e) {
throw new Exception(e.toString());
}
}
throws是用来声明一个方法可能抛出的所有异常信息
throw则是指抛出的一个具体的异常类型.
通常在一个方法(类)的声明处通过throws声明方法(类)可能抛出的异常信息,而在方法(类)内部通过throw声明一个具体的异常信息.
throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法;
throw则需要用户自己捕获相关的异常,而后在对其进行相关包装,最后在将包装后的异常信息抛
13.equals()和==比较两个字符串是否相同有什么区别
答:(1). == 是一个运算符。
(2).Equals则是string对象的方法,可以重写,自定义在什么情况下相等
我们比较无非就是这两种 1、基本数据类型比较 2、引用对象比较
1、基本数据类型比较
==和Equals都比较两个值是否相等。相等为true 否则为false;
2、引用对象比较
==和Equals都是比较栈内存中的地址是否相等 。相等为true 否则为false;
需注意几点:
1、string是一个特殊的引用类型。对于两个字符串的比较,不管是 == 和 Equals 这两者比较的都是字符串是否相同;
2、当你创建两个string对象时,内存中的地址是不相同的,你可以赋相同的值。
所以字符串的内容相同。引用地址不一定相同,(相同内容的对象地址不一定相同),但反过来却是肯定的;
3、基本数据类型比较(string 除外) == 和 Equals 两者都是比较值;
14.java的权限修饰符有哪几种,它们的可见性分别是什么
答: (1)private:类的内部可以访问,修饰属性最合适
(2)default:同一个包下可以访问
(3)protected:同一个包下可以访问,不同包的子类可以访问
(4)public:可以被所有的类访问,公共修饰符
15.说出能用于switch()后的括号中的数据类型
答:java 1.6(包括)以前,只是支持等价成int 基本类型的数据:byte ,short,char,int(其他的都不可以)。
1.7加入的新特性可以支持String类型的数据。
16.throw、throws、try、catch、finally他们在java异常机制中起到的作用
答: throws是获取异常,throw是抛出异常,try是将会发生异常的语句括起来,从而进行异常的处理,catch是如果有异常就会执行他里面的语句,而finally不论是否 有异常都会进行执行的语句。
throw 仅用于方法定义后面,指示该方法可能会抛出什么异常,使用该方法的方法必须处理该异常,或者再次抛出。
throws 用于当程序判断发生异常时,用该语句抛出异常,或处理异常时再次抛出异常。
//下面三个关键字就是处理异常
try {
//这里放可能会发生异常的语句
} catch(Exception e) {
//这里处理异常
} finally {
//这里的语句必然会得到执行,不管异常发省与否,
//用于关闭数据库,关闭连接等收尾操作(非必要)
}
java异常的一个简单例子,比如我有一个除法方法
public int divide(int a, int b) {
return a / b;
}
但是这就有一个问题,当b是0时,程序会报错。
如果引入异常,改成这样
public int divide(int a, int b) throws Exception {
if (b == 0) {
throw new Exception("b = 0");
}
return a / b;
}
17.包的意义:
答:Package的作用就是把若干类按包结构进行分类管理。其中最重要的用途是为了解决同名但作用不同的类同时存在的问题
在程序设计中,是有分层次的,比如说
我将所有跟表层有关的类放在一个包里(Action)
将逻辑操作的类放在另一个包里(Service)
将数据库的操作放在其他包里(DAO)
那么这样程序的结构就很清楚了。。。
还有一个作用是解决同名类的问题
1.管理类的集合, 2.protected作用域范围同包下可访问此修饰符的变量和方法
18.接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实体类(concreteclass)?
答:1.接口可以继承接口..但是要使用extends~而不是用implements
如:interface a{}
interface b extends a{}
2.抽象类可以实现接口..
比如java.util中的AbstractCollection类就是实现的Collection接口
3.抽象类可以继承实体类
19.当类被加载是,请简述一下类中的静态声明执行顺序
答:静态代码块是程序首先执行的,而且先执行父类再执行子类的,并且有几个对象只执行一次静态代码块。
其次是从程序主方法开始执行,再执行非静态代码块和无参构造函数,而且仍然是先执行父类再执行子类的。
如果子类含有有参的构造函数,那么执行子类的有参构造函数,就不执行子类的无参构造函数了,但同样要执行父类的无参构造函数。
看到这里你会发现,非静态代码块和静态代码块的区别在于非静态代码块和构造函数一样,需要创建一次对象就执行一次的。
随后执行子类的成员函数,如果子类的成员函数重写了父类的成员函数,则只执行子类的不执行父类的。
最后是主函数,因为主函数一个程序只有一个,所以只执行一次本程序的主函数。
20.多态的好处
答:多态体现为两种方式:重写和重载
重写是父子类之间多态的体现,它的好处就是可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
重载是本类之间多态的体现,它的好处是可以满足用户在针对同一对象可以调用同一方法的不同功能体现,以最大限度适应用户的不同需求。
21.类与对象的关系
答:类是拥有相同行为特征对象的一个抽象概念,而对象是类这个抽象概念中事实存在的个体。
22.静态方法注意事项
答:静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带 static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
1,静态方法不能访问非静态的成员。
但是非静态可以访问静态成员的。
说明:静态的弊端在于访问出现局限性。好处是可以直接被类名调用。
2,静态方法中不允许出现this,super关键字。
为什么不行呢?
原理揭秘:
1,静态是随着类的加载就加载了。也是随着类的消失而消失了。
2,静态优先于对象存在,被对象共享。
3,因为静态先存在于内存中无法访问后来的对象的中的数据,所以静态无法访问非静态。
而且内部无法书写this。因为这时对象有可能不存在,this没有任何指
23.int和Integer有什么区别(基本数据类跟包装器类有什么区别?)
答:
int是java提供的8种原始数据类型之一,Integer是java为int提供的封装类。int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,
②两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存
③两个都是new出来的,都为false
④int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比
1.int是基本的数据类型;
2.Integer是int的封装类;
3.int和Integer都可以表示某一个数值;
4.int和Integer不能够互用,因为他们两种不同的数据类型;
5. Integer 是对象类型 int是原始类型 适用场合有很大的不同 之所以要把int封装成Integer 型 是因为很多方法参数就只接收对象类型(Object) 还比如 范型 就
24.子类与父类的生成顺序关系?
答:Java 技术安全模式要求在子类执行任何东西之前,描述父类的一个对象的各个方面都必须初始化。因此,Java 编程语言总是在执行子构造方法前调用父类构造方法的版本。有继承的类在运行的时候,一定要记得:初始化子类必先初始化父类,这是Java 程序的一个基本运行过程
25. 两个对象值相同(x.equals(y)==true),但却可有不同的hashcode,这句话对不对?
答:很对!
如果对象要保存在HashSet或HashMap中,它们的equals相等,那么,它们的hashcode值就必须相等。
如果不是要保存在HashSet或HashMap,则与hashcode没有什么关系了,这时候hashcode不等是可以的,
值相同使用equals方法来判断,equals方法重写后不一定是判断对象是否是同一个对象
所以hashcode不同是很正常的
就好比我定义个类,有名字和编号
我重写equals方法,让名字相同就返回相等
那么我虽然有hashcode不同的两个对象(他们的编号都可以不同,或者两个对象的所有属性值都一样)
但他们的hashcode当然不同
因为根本就不是一个对象。
补充说明:
Q:HashCode()是什么?
A:hashcode 可以理解为 java对象的唯一身份证号。
Q:equals()是什么?
A:equals()方法是继承于所有对象的鼻祖Object,意思是“是否相同”。对于对象来说就是比较 两个对象是否有相同的hashcode.
另:equals()方法是可以覆写的。也就是说,你可以指定equals的判别依据,对于对象而言默认是hashcode。
26.float f=3.4这个表达式是否正确?
答:
不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。
补充:
float是单精度类型,精度是6位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间
double是双精度类型,精度是15位有效数字,取值范围是10的-308次方到10的308次方,double占用8个字节的存储空间
当你不声明的时候,默认小数都用double来表示,所以如果要用float的话,则应该在其后加上f
例如:float a=1.3;
则会提示不能将double转化成float? 这成为窄型转化
如果要用float来修饰的话,则应该使用float a=1.3f
注意float是6位有效数字,第7位数字将会产生四舍五入
27.char a=‘晕‘;char能不能存放一个中文?为什么
可以。JAVA默认的编码是UNICODE.不是ASCII的char
现有程序可供测试:
但若理解成
s=‘me‘ 中放一个汉字,就不可以了,因为中文占16个字节,满了。
java采用unicode,2个字节(16位)来表示一个字符, 无论是汉字还是数字字母,或其他语言。
char 在java中是2个字节。
所以可以存储中文。
28.instanceof是什么东东?
答:
判断数据类型的,或者对象是否为类的实例,如果是就返回true;否则返回false
30.当类被加载是,请简述一下类中的静态声明执行顺序
答:
1 不管是静态方法还是非静态方法,都需要调用后执行,其执行的次序和在类里声明的次序无关,区别是静态方法是“class.method"方式执行,非静态方法是"object.method"方式执行,即后者需要创建一个对象。
2 静态成员变量(也称类变量)先于非静态成员变量初始化,静态成员变量在类第一次加载时初始化,所有对象共享一份静态成员变量,非静态成员变量则在对象创建时初始化
补充:
只加载一次,而且是懒加载的,第一次调用该类的时候加载(比如当调用该类的静态方法或者成员变量,new一个该类的对象的时候)。
具体的说,每一个类(.class)文件,都对应着一个Class对象,这个Class对象类似于一个模板,用于创建该类的对象。这个Class对象在第一次调用该类时创建并加载到java虚拟机中。
31.面向对象的特点,各有什么特点?
答:简单的说有封装,抽象,继承,多态
封装:
封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。
例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人以后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。
抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,如下:
classPerson{
String name;
int age;
}
继承:
在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
多态:
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性增强了软件的灵活性和扩展性。
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。JAVA引用变量有两个类型:一个是编译时的类型,一个是运行时的类型,编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就会出现所谓的多态(Polymorphism)。
多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
32.String和StringBuffer的区别
答:
简单地说,就是一个变量和常量的关系。StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。
StringBuffer的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。
StringBuffer:StringBuffer类属于一种辅助类,可预先分配指定长度的内存块建立一个字符串缓冲区。
StringBuffer是线程安全的,在多线程程序中也可以很方便的进行使用,但是程序的执行效率相对来说就要稍微慢一些。
StringBuffer的常用方法
StringBuffer类中的方法要偏重于对字符串的变化例如追加、插入和删除等,这个也是StringBuffer和String类的主要区别。
1、append方法
public StringBuffer append(boolean b)
该方法的作用是追加内容到当前StringBuffer对象的末尾,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也发生改变,例如:
StringBuffer sb = new StringBuffer(“abc”);
sb.append(true);
则对象sb的值将变成”abctrue”。
使用该方法进行字符串的连接,将比String更加节约内容,例如应用于数据库SQL语句的连接,例如:
33.运行时异常与一般异常有何异同?
答:
Java提供了两类主要的异常:运行时异常runtime exception和一般异常checked exception。checked 异常。对于后者这种异常,JAVA要求程序员对其进行catch。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。
运行时异常我们可以不处理。这样的异常由虚拟机接管。出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
34.说出ArrayList,Vector,LinkedList的存储性能和特性
答:
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用。
35.Collection和Collections的区别。
答:
Collection是集合类的上级接口,继承与他的接口主要有Set和List.
Collections是一个包装类,是针对集合类的一个帮助类,此类完全由在 collection 上进行操作或返回 collection 的静态方法组成,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
36.&和&&的区别。&,|,~,>>,<< ,>>>
答:
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null&& !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 &++y>0) y会增长,If(x==33 && ++y>0)不会增长
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。
备注:这道题先说两者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来表明自己理解透彻深入、实际经验丰富。
<<表示左移, 左移一位表示原来的值乘2.
”右移位 运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。有符号”右移位运算符使用了 “符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。Java 也添加了一种“无符号”右 移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。”|”或的意思。
~是位运算符,意义是
按位非(NOT)
按位非也叫做补,一元运算符NOT“~”是对其运算数的每一位取反。例如,数字42,它的二进制代码为:
00101010
经过按位非运算成为
11010101
优先级按位运算符的优先级,在运算符中优先级最低。
37.HashMap和Hashtable的区别。
答:
(条理上还需要整理,也是先说相同点,再说不同点)
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,在只有一个线程访问的情况下,效率要高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供外同步。
38.final,finally,finalize的区别
答:
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型,例如,一段代码……
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用
39.sleep()和wait()有什么区别?
答:
(网上的答案:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。)
sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果),调用wait方法的线程就会解除wait状态和程序可以再次得到锁后继续向下运行。对于wait的讲解一定要配合例子代码来说明,才显得自己真明白。
40.Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
答:
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
至于Overloaded的方法是否可以改变返回值的类型这个问题,要看你倒底想问什么呢?这个题目很模糊。如果几个Overloaded的方法的参数列表不一样,它们的返回者类型当然也可以不一样。但我估计你想问的问题是:如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Overload。这是不行的,我们可以用反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果,例如,我们调用map.remove(key)方法时,虽然remove方法有返回值,但是我们通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
41.error和exception有什么区别?
答:
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
41.同步和异步有何异同,在什么情况下分别使用他们?举例说明。
答:
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。
42.abstract class和interface有什么区别?
答:
abstract
类不能创建的实例对象。含有abstract方法的类必须定义为abstractclass,
abstractclass类中的方法不必是抽象的。
abstractclass类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。
如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。
接口中的方法定义默认为publicabstract类型,接口中的成员变量类型默认为
public staticfinal。
下面比较一下两者的语法区别:1.
抽象类可以有构造方法,接口中不能有构造方法。2.
抽象类中可以有普通成员变量,接口中没有普通成员变量3.
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。4.
抽象类中的抽象方法的访问类型可以是public,
protected和(默认类型,
虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为publicabstract类型。5.
抽象类中可以包含静态方法,接口中不能包含静态方法6.
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是
public staticfinal类型,并且默认即为
一个类可以实现多个接口,但只能继承一个抽象类。
43.heap栈内存和stack堆内存有什么区别。
答:
java的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。
堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用new创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用final修饰后,放在堆中,而不是栈中。
44.StaticNestedClass和InnerClass的不同。
答
内部类就是在一个类的内部定义的类,内部类中不能定义静态成员(静态成员不是对象的特性,只是为了找一个容身之处,所以需要放到一个类中而已,这么一点小事,你还要把它放到类内部的一个类中,过分了啊!提供内部类,不是为让你干这种事情,无聊,不让你干。我想可能是既然静态成员类似c语言的全局变量,而内部类通常是用于创建内部对象用的,所以,把“全局变量”放在内部类中就是毫无意义的事情,既然是毫无意义的事情,就应该被禁止),内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中
最后,在方法外部定义的内部类前面可以加上static关键字,从而成为Static Nested Class,它不再具有内部类的特性,所有,从狭义上讲,它不是内部类。Static Nested Class与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差别,它可以定义成public、protected、默认的、private等多种类型,而普通类只能定义成public和默认的这两种类型。在外面引用Static Nested Class类的名称为“外部类名.内部类名”。在外面不需要创建外部类的实例对象,就可以直接创建Static Nested Class,例如,假设Inner是定义在Outer类中的Static Nested Class,那么可以使用如下语句创建Inner类:
Outer.Inner inner = new Outer.Inner();
由于static Nested Class不依赖于外部类的实例对象,所以,static Nested Class能访问外部类的非static成员变量。当在外部类中访问Static Nested Class时,可以直接使用Static Nested Class的名字,而不需要加上外部类的名字了,在Static Nested Class中也可以直接引用外部类的static的成员变量,不需要加上外部类的名字。
在静态方法中定义的内部类也是Static Nested Class,这时候不能在类前面加static关键字,静态方法中的Static Nested Class与普通方法中的内部类的应用方式很相似,它除了可以直接访问外部类中的static的成员变量,还可以访问静态方法中的局部变量,但是,该局部变量前必须加final修饰符。
45.GC是什么?为什么要有GC?
答:
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
46.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编译器会对它进行特殊处理,因此可以正确编译。
47.Java有没有goto?
答:java中的保留字,现在没有在java中使用。
48.启动一个线程是用run()还是start()?
答:
启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。
49.给我一个你最常见到的runtimeexception。
答:
RuntimeException是java中所有运行时异常的父类,实际运行时出现的都是它的子类,看看RuntimeException的Java doc就可以随便列出几个:
Object x = newInteger(0);
System.out.println((String)x);
当试图将对象强制转换为不是实例的子类时,抛出该异常(ClassCastException)
int a=5/0;一个整数“除以零”时,抛出ArithmeticException异常。
String s=null;int size=s.size();当应用程序试图在需要对象的地方使用 null 时,抛出NullPointerException异常
"hello".indexOf(-1);
指示索引或者为负,或者超出字符串的大小,抛出StringIndexOutOfBoundsException异常
String[] ss=new String[-1];
如果应用程序试图创建大小为负的数组,则抛出NegativeArraySizeException异常。
50.接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实体类(concreteclass)?
答:
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可以继承具体类。抽象类中可以有静态的main方法。
备注:只要明白了接口和抽象类的本质和作用,这些问题都很好回答,你想想,如果你是java语言的设计者,你是否会提供这样的支持,如果不提供的话,有什么理由吗?如果你没有道理不提供,那答案就是肯定的了。
只有记住抽象类与普通类的唯一区别:就是不能创建实例对象和允许有abstract方法。
51.List,Set,Map是否继承自Collection接口?
答:
List,Set是,Map不是
52.abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
答:
都不可以,因为abstract申明的方法是要求子类去实现的,abstract只是告诉你有这样一个接口,你要去实现,至于你的具体实现可以是native和synchronized,也可以不是,抽象方法是不关心这些事的,所以写这两个是没有意义的。然后,static方法是不会被覆盖的,而abstract方法正是要子类去覆盖它,所以也是没有意义的。所以,总的来说,就是Java语法不允许你这样做,事实上,也没有意义这样做。
abstract的method不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与abstract混用。例如,FileOutputSteam类要硬件打交道,底层的实现用的是操作系统相关的api实现,例如,在windows用c语言实现的,所以,查看jdk的源代码,可以发现FileOutputStream的open方法的定义如下:
private native void open(Stringname) throws FileNotFoundException;
如果我们要用java调用别人写的c语言函数,我们是无法直接调用的,我们需要按照java的要求写一个c语言的函数,又我们的这个c语言函数去调用别人的c语言函数。由于我们的c语言函数是按java的要求来写的,我们这个c语言函数就可以与java对接上,java那边的对接方式就是定义出与我们这个c函数相对应的方法,java中对应的方法不需要写具体的代码,但需要在前面声明native。
关于synchronized与abstract合用的问题,我觉得也不行,因为在我几年的学习和开发中,从来没见到过这种情况,并且我觉得synchronized应该是作用在一个具体的方法上才有意义。而且,方法上的synchronized同步所使用的同步锁对象是this,而抽象方法上无法确定this是什么。
数组有没有length()这个方法?String有没有length()这个方法?
53.
答:
数组没有length()这个方法,有length的属性。String有有length()这个方法。用来的到字符串的长度。
54.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是equals()?它们有何区别?
答:
Set里的元素是不能重复的,元素重复与否是使用equals()方法进行判断的。
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
55.----55.构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
----56.是否可以继承String类?
String类是final类故不可以继承。
----57.swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量(更大字体),整数表 达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int, 所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。
----58.try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,
什么时候被执行,在return前还是后?
也许你的答案是在return之前,但往更细地说,我的答案是在return中间执行,请看下面程序代码的运行结果:
运行结果是1,为什么呢?主函数调用子函数并得到结果的过程,好比主函数准备一个空罐子,当子函数要返回结果时,先把结果放在罐子里,然后再将程序逻辑返回到主函数。所谓返回,就是子函数说,我不运行了,你主函数继续运行吧,这没什么结果可言,结果是在说这话之前放进罐子里的。
-----59.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
值传递 就是在方法调用的时候,实参是将自己的一份拷贝赋给形参,在方法内,对该参数值的修改不影响原来实参,常见的例子就是刚开始学习c语言的时候那个交换方法的例子了。
引用传递 是在方法调用的时候,实参将自己的地址传递给形参,此时方法内对该参数值的改变,就是对该实参的实际操作。
在java中只有一种传递方式,那就是值传递.可能比较让人迷惑的就是java中的对象传递时,对形参的改变依然会影响到该对象的内容。
----60.当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
分几种情况:
1. 其他方法前是否加了synchronized关键字,如果没加,则能。
2. 如果这个方法内部调用了wait,则可以进入其他synchronized方法。
3. 如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。
4. 如果其他方法是static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是this。
-----61.编程题:写一个Singleton出来。
第一种:饱汉模式
public classSingleTon {
private SingleTon(){
}
//实例化放在静态代码块里可提高程序的执行效率,但也可能更占用空间
private final static SingleTon instance =new SingleTon();
public static SingleTon getInstance(){
return instance;
}
}
第二种:饥汉模式
public classSingleTon {
private SingleTon(){}
private static instance = null;//newSingleTon();
public static synchronized SingleTongetInstance(){
if(instance == null)
instance = new SingleTon();
return instance;
}
}
第三种:用枚举
public enum SingleTon{
ONE;
}
第三:更实际的应用(在什么情况用单例)
public classSequenceGenerator{
//下面是该类自身的业务功能代码
private int count = 0;
public synchronized int getSequence(){
++count;
}
//下面是把该类变成单例的代码
private SequenceGenerator(){}
private final static instance = newSequenceGenerator();
public static SingleTon getInstance(){
return instance;
}
}
第四:
public class MemoryDao
{
private HashMap map = new HashMap();
publicvoid add(Student stu1){
map.put(SequenceGenerator.getInstance().getSequence(),stu1);
}
//把MemoryDao变成单例
}
Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
一般Singleton模式通常有几种种形式:
第一种形式: 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪?
//注意这是private只供内部调用
private staticSingleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public staticSingleton getInstance() {
return instance;
}
}
第二种形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance;
}
}
其他形式:
定义一个类,它的构造函数为private的,所有方法为static的。
一般认为第一种形式要更加安全些
-----63.Java中的异常处理机制的简单原理和应用。
异常是指java程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间、地点、人物、情节等信息,可以用一个对象来表示,Java使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封装到一个对象来表示的,该对象中包含有异常的信息。
Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception,Error表示应用程序本身无法克服和恢复的一种严重问题,程序只有死的份了,例如,说内存溢出和线程死锁等系统问题。Exception表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException);普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。
java为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须try..catch处理或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常,而系统异常可以处理也可以不处理,所以,编译器不强制用try..catch处理或用throws声明,所以系统异常也称为unchecked异常。
提示答题者:就按照三个级别去思考:虚拟机必须宕机的错误,程序可以死掉也可以不死掉的错误,程序不应该死掉的错误;
----64.垃圾回收的优点和原理。并考虑2种回收机制。
Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
----65.请说出你所知道的线程同步的方法。
用synchronized关键字修饰同步方法。
同步有几种实现方法分别是synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。
给一个方法增加synchronized修饰符之后就可以使它成为同步方法,这个方法可以是静态方法和非静态方法,但是不能是抽象类的抽象方法,也不能是接口中的接口方法。下面代码是一个同步方法的示例:
public synchronized void aMethod() {
// do something
}
public static synchronized void anotherMethod() {
// do something
}
线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。
同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;而同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。如果这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。
-----66.你所知道的集合类都有哪些?主要方法?
最常用的集合类是 List 和 Map。 List的具体实现包括 ArrayList和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List适用于按数值索引访问元素的情形。
Map 提供了一个更通用的元素存储方法。 Map集合类用于存储元素对(称作"键"和"值"),其中每个键映射到一个值。
ArrayList/VectoràList
àCollection
HashSet/TreeSetàSet
PropetiesàHashTable
àMap
Treemap/HashMap
我记的不是方法名,而是思想,我知道它们都有增删改查的方法,但这些方法的具体名称,我记得不是很清楚,对于set,大概的方法是add,remove, contains;对于map,大概的方法就是put,remove,contains等,因为,我只要在eclispe下按点操作符,很自然的这些方法就出来了。我记住的一些思想就是List类会有get(int index)这样的方法,因为它可以按顺序取元素,而set类中没有get(int index)这样的方法。List和set都可以迭代出所有元素,迭代时先要得到一个iterator对象,所以,set和list类都有一个iterator方法,用于返回那个iterator对象。map可以返回三个集合,一个是返回所有的key的集合,另外一个返回的是所有value的集合,再一个返回的key和value组合成的EntrySet对象的集合,map也有get方法,参数是key,返回值是key对应的value。
------67.描述一下JVM加载class文件的原理机制?
JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备、解析
装载:查找和导入类或接口的二进制数据;
链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
校验:检查导入类或接口的二进制数据的正确性;
准备:给类的静态变量分配并初始化存储空间;
解析:将符号引用转成直接引用;
初始化:激活类的静态变量,初始化Java代码和静态Java代码块
----68.多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException(中断异常)异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
-----69.线程的基本概念、线程的基本状态以及状态之间的关系
一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有一个线程,即main方法执行的那个线程。如果只是一个cpu,它怎么能够同时执行多段程序呢?这是从宏观上来看的,cpu一会执行a线索,一会执行b线索,切换时间很快,给人的感觉是a,b在同时执行,好比大家在同一个办公室上网,只有一条链接到外部网线,其实,这条网线一会为a传数据,一会为b传数据,由于切换时间很短暂,所以,大家感觉都在同时上网。
状态:就绪,运行,synchronize阻塞,wait和sleep挂起,结束。wait必须在synchronized内部调用。
调用线程的start方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到synchronized语句时,由运行状态转为阻塞,当synchronized获得锁后,由阻塞转为运行,在这种情况可以调用wait方法转为挂起状态,当线程关联的代码执行完后,线程变为结束状态。
---70.简述位操作(&,|,^)与逻辑操作(&&,||)的区别。
a.条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型?
b.逻辑操作不会产生短路.如:?
int a = 0;?
int b = 0;?
if( (a = 3) > 0 || (b = 3) > 0 ) //操后a =3,b=0.?
if( (a = 3) > 0 | (b = 3) > 0 ) //操后a =3,b=3。!!!需要更改
-----71.简述synchronized和java.util.concurrent.locks.Lock的异同?
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。
-----72.JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
Java?通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并
?提供了良好的接口。在?Java?中,每个异常都是一个对象,它是?Throwable?类或
其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有
异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java?的异常
处理是通过?5?个关键词来实现的:try、catch、throw、throws?和?finally。一
般情况下是用?try?来执行一段程序,如果出现异常,系统会抛出(throws)一个
异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺
省处理器来处理;
try?用来指定一块预防所有“异常”的程序;
catch?子句紧跟在?try?块后面,用来指定你想要捕捉的“异常”的类型;
throw?语句用来明确地抛出一个“异常”;
throws?用来标明一个成员函数可能抛出的各种“异常”;
Finally?为确保一段代码不管发生什么“异常”都被执行一段代码;
可以在一个成员函数调用的外面写一个?try?语句,在这个成员函数内部写另一
个?try?语句保护其他代码。每当遇到一个?try?语句,“异常”的框架就放到堆栈
上面,直到所有的?try?语句都完成。如果下一级的?try?语句没有对某种“异常”
进行处理,堆栈就会展开,直到遇到有处理这种“异常”的?try?语句。
-----73.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?
可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。
------74.java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?
java5以前,有如下两种:
第一种:
new Thread(){}.start();这表示调用Thread子类对象的run方法,new Thread(){}表示一个Thread的匿名子类的实例对象,子类加上run方法后的代码如下:
new Thread(){
public void run(){
}
}.start();
第二种:
new Thread(new Runnable(){}).start();这表示调用Thread对象接受的Runnable对象的run方法,new Runnable(){}表示一个Runnable的匿名子类的实例对象,runnable的子类加上run方法后的代码如下:
new Thread(new Runnable(){
public voidrun(){
}
}
).start();
从java5开始,还有如下一些线程池创建多线程的方式:
ExecutorService pool = Executors.newFixedThreadPool(3)
for(int i=0;i<10;i++)
{
pool.execute(newRunable(){public void run(){}});
}
Executors.newCachedThreadPool().execute(new Runable(){publicvoid run(){}});
Executors.newSingleThreadExecutor().execute(new Runable(){publicvoid run(){}});
有两种实现方法,分别使用new Thread()和new Thread(runnable)形式,第一种直接调用thread的run方法,所以,我们往往使用Thread子类,即new SubThread()。第二种调用runnable的run方法。
有两种实现方法,分别是继承Thread类与实现Runnable接口
用synchronized关键字修饰同步方法
反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。
-----75.java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
字节流,字符流。字节流继承于?InputStream、OutputStream,字符流继承
于?Reader、Writer。在?Java.io?包中还有许多其他的流,主要是为了提高性能
和使用方便。
-----76.java中会存在内存泄漏吗,请简单描述。
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收:
java中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中可能出现内存泄露的情况,例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中),然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。
检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
下面内容来自于网上(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让它从数组中消失,将那个元素所在的位置的值设置为null即可):
我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子不是我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。
例子1
public class Bad{
public static Stack s=Stack();
static{
s.push(new Object());
s.pop(); //这里有一个对象发生内存泄露
s.push(new Object()); //上面的对象可以被回收了,等于是自愈了
}
}
因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很容易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!
内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
-----77.java中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。(这里引用变量的类型指定的就是下面例子的中的父类A)
父类A有一个方法function(),子类B,C分别继承A并且重写function(),当创建一个对象A b = new B(); b.function()就调用B的funciotn,假如你new C(),那调用的就是C重写的function。怎么判断使用那个类的function就是动态绑定
------78.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
----79.静态变量和实例变量的区别?
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
例如,对于下面的程序,无论创建多少个实例对象,永远都只分配了一个staticVar变量,并且每创建一个实例对象,这个staticVar就会加1;但是,每创建一个实例对象,就会分配一个instanceVar,即可能分配多个instanceVar,并且每个instanceVar的值都只自加了1次。
Public class Student{
Static int staticVar ;
Int instanceVar;
Public Student(){
staticVar = staticVar + 1;
instanceVar = instanceVar + 1;
}
}
----80.什么是java序列化,如何实现java序列化?
我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,例如,要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输,但是,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java帮我们做,要被传输的对象必须实现serializable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。需要被序列化的类必须实现Serializable接口,该接口是一个mini接口,其中没有需要实现的方法, implements Serializable只是为了标注该对象是可被序列化的。
例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable接口。
-----81.在JAVA中,如何跳出当前的多重嵌套循环?
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break语句,即可跳出外层循环。例如,
ok:
for(int i=0;i<10;i++) {
for(int j=0;j<10;j++) {
System.out.println(“i=” + i + “,j=” + j);
if(j == 5) break ok;
}
}
另外,我个人通常并不使用标号这种方式,而是让外层的循环条件表达式的结果可以受到里层循环体代码的控制,例如,要在二维数组中查找到某个数字。
int arr[][] ={{1,2,3},{4,5,6,7},{9}};
boolean found = false;
for(int i=0;i<arr.length&& !found;i++) {
for(int j=0;j<arr[i].length;j++){
System.out.println(“i=” + i + “,j=” + j);
if(arr[i][j] ==5) {
found = true;
break;
}
}
}
----82.List、Map、Set三个接口,存取元素时,各有什么特点?
这样的题属于随意发挥题:这样的题比较考水平,两个方面的水平:一是要真正明白这些内容,二是要有较强的总结和表述能力。如果你明白,但表述不清楚,在别人那里则等同于不明白。
首先,List与Set具有相似性,它们都是单列元素的集合,所以,它们有一个功共同的父接口,叫Collection。Set里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象,即假设Set集合中有了一个A对象,现在我要向Set集合再存入一个B对象,但B对象与A对象equals相等,则B对象存储不进去,所以,Set集合的add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true,当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。Set取元素时,没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。
List表示有先后顺序的集合,注意,不是那种按年龄、按大小、按价格之类的排序。当我们多次调用add(Obj e)方法时,每次加入的对象就像火车站买票有排队顺序一样,按先来后到的顺序排序。有时候,也可以插队,即调用add(int index,Obj e)方法,就可以指定当前对象在集合中的存放位置。一个对象可以被反复存储进List中,每调用一次add方法,这个对象就被插入进集合中一次,其实,并不是把这个对象本身存储进了集合中,而是在集合中用一个索引变量指向这个对象,当这个对象被add多次时,即相当于集合中有多个索引指向了这个对象,如图x所示。List除了可以以Iterator接口取得所有的元素,再逐一遍历各个元素之外,还可以调用get(index i)来明确说明取第几个。
Map与List和Set不同,它是双列的集合,其中有put方法,定义如下:put(obj key,objvalue),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。取则可以根据key获得相应的value,即get(Object key)返回值为key所对应的value。另外,也可以获得所有的key的集合,还可以获得所有的value的集合,还可以获得key和value组合成的Map.Entry对象的集合(Map类提供了一个称为entrySet()的方法,这个方法返回一个Map.Entry实例化后的对象集合)。
Map map = new Map();
Set <Map.Entry<String, String>> entry = map.entrySet();//entry就是Map.Entry //实例化后的对象集合
List 以特定次序来持有元素,可有重复元素。Set无法拥有重复元素,内部排序。Map保存key-value值,value可多值。
HashSet按照hashcode值的某种运算方式进行存储,而不是直接按hashCode值的大小进行存储。例如,"abc"---> 78,"def" ---> 62,"xyz" ---> 65在hashSet中的存储顺序不是62,65,78,这些问题感谢以前一个叫崔健的学员提出,最后通过查看源代码给他解释清楚,看本次培训学员当中有多少能看懂源码。LinkedHashSet按插入的顺序存储,那被存储对象的hashcode方法还有什么作用呢?学员想想!hashset集合比较两个对象是否相等,首先看hashcode方法是否相等,然后看equals方法是否相等。new两个Student插入到HashSet中,看HashSet的size,实现hashcode和equals方法后再看size。
同一个对象可以在Vector中加入多次。往集合里面加元素,相当于集合里用一根绳子连接到了目标对象。往HashSet中却加不了多次的。
---83.说出一些常用的类,包,接口,请各举5个
要让人家感觉你对java ee开发很熟,所以,不能仅仅只列core java中的那些东西,要多列你在做ssh项目中涉及的那些东西。就写你最近写的那些程序中涉及的那些类。
常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer
java.util.Date,System,Class,List,HashMap
常用的包:java.lang java.io java.util java.sql,javax.servlet,org.apache.strtuts.action,org.hibernate
常用的接口:Remote List Map Document NodeList,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)、Session(Hibernate),HttpSession
----84.谈谈final, finally, finalize的区别
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量(方法内的变量)必须定义成final类型,例如,一段代码……
Public class Outer{
Private String name = “林青霞”;
Private int age = 27 ;
Public static void method(){
Int age02 = 30;
}
Class inner{
Int age03 = age + age02;// 报错;age02是外部类方法内的变量,即局部变量,而 //内部类要访问局部变量,局部变量(方法内的变量)必须定
//义成final类型,所以这段代码会报错。
}
}
finally是异常处理语句结构的一部分,表示总是执行。
即使try{}代码中有return语句,也会将finally代码执行完再返回。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用
---85.String和StringBuffer 的区别
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据。另外,String实现了equals方法,new String(“abc”).equals(newString(“abc”)的结果为true,而StringBuffer没有实现equals方法,所以,new StringBuffer(“abc”).equals(newStringBuffer(“abc”)的结果为false。
接着要举一个具体的例子来说明,我们要把1到100的所有数字拼起来,组成一个串。
StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{
sbf.append(i);
}
上面的代码效率很高,因为只创建了一个StringBuffer对象,而下面的代码效率很低,因为创建了101个对象。
String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}
在讲两者区别时,应把循环的次数搞成10000,然后用endTime-beginTime来比较两者执行的时间差异,最后还要讲讲StringBuilder与StringBuffer的区别。
{ 1. 在执行速度方面的比较:StringBuilder > StringBuffer
2. StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了。
3. StringBuilder:线程非安全的
StringBuffer:线程安全的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
对于三者使用的总结:1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
}
String覆盖了equals方法和hashCode方法,而StringBuffer没有覆盖equals方法和hashCode方法,所以,将StringBuffer对象存储进Java集合类中时会出现问题。
标签:消失 面试题 竞争 开发 不可变 操作 单线程 布尔 索引
原文地址:http://www.cnblogs.com/zlazm/p/7898596.html