- Java的子类不能获得父类的构造器,但在子类构造器中可以调用父类构造器的初始化代码。
- 严格讲,Java类只能有一个父类,这种说法是错误的,应该换成如下说法:Java类只能有一个直接父类。实际上,Java可以有无限多个间接父类。
- 如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的实例变量,而不是该类自己定义的实例变量。
- 在继承中,实例变量也会发生类似于函数覆盖的情况,即若子类中定义了和匪类中同名的实例变量,则会默认访问子类中的实例变量
- 在子类中访问父类中定义的被隐藏的实例变量和父类中定义的被覆盖的方法,可以通过super.作为限定来调用父类中的这些实例变量和实例方法。
- 父类构造器总会在子类构造器之前执行。所以,创建任何Java对象,一层一层向上,最先执行的总是java.lang.Object类的构造器。
- 对象的实例变量不具备多态性,只有方法才具备多态性
- 引用变量在编译时只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。
- 尽量不要在父类构造器中调用将要被子类重写的方法。因为:当系统试图创建子类对象时,会先执行其父类构造器,如果父类构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法。
- a instanceof B 中 a必须为B类的实例 或 B的子类的实例。
- final修饰的方法不能被重写,但是可以被重载。
final修饰的成员变量只能被赋值一次,
静态变量,可以在声明变量时赋值或者在静态代码块里赋值。
非静态变量,可以在声明变量时赋值或者在代码块里赋值或者在构造函数中赋值。
final修饰的变量如果在初始化的时候就被赋值,而且=右边的值是常数或者常数的表达式,那就可以执行宏替换,也就是把代码里所有出现该final变量的地方都替换成常量。例如:final String s1 = "45"; final String s2 = "6"; String s3 = s1 + s2; final String s4 = "456"; System.out.println(s3 == s4);
将输出 true
要保证两个用equals()方法判断为相等的对象的hashCode()也相等。
- 所有的局部成员都不能用static修饰,也不能使用访问控制符修饰
- 匿名内部类不能重复使用
- 匿名内部类不能使用抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类对象。因此不允许将匿名内部类定义成抽象类。
- 匿名内部类不能定义构造器。因为匿名内部类没有类名。但是可以通过定义初始化块来完成构造器应该做的初始化工作。
- 当通过父类来创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似是指拥有相同的形参列表。
- 当通过实现接口来创建匿名内部类对象时,匿名内部类只有一个隐式的无参构造器,所以new 接口名() –>这个后面的括号里不能传入参数。
- 当创建匿名内部类时,必须实现接口或抽象父类中的所有方法。因为创建匿名内部类就意味着创建了匿名内部类对象,所以不能再有抽象方法存在。 如果有需要,也可以重写父类的普通方法。
- Java8之前,Java要求被局部内部类(不常见),匿名内部类访问的局部变量a必须使用final修饰。java8开始没有这个限制,自动给你加上final了。也就是说这个变量a只能被赋值一次。
- 在某些情况下,一个类的对象是有限的,如季节类,只有春夏秋冬四个类。这样的类被称为枚举类。
- 使用枚举类可以使程序更加健壮,避免创造对象的随意性。Java从JDK1.5后就增加了对枚举类的支持。同时,switch也支持枚举类型。
- 枚举类的enum关键字和class interface的地位相同。把枚举类当成类就好。它是一种特殊的类,类的规则基本适用于枚举类。
- 枚举类的构造器只能(也是默认)用private修饰,加或不加都是private。 非抽象的枚举类默认会使用final修饰。
- 垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(数据库连接,网络IO等资源)。
- 根据对象在堆内存中被引用变量所引用的状态,对象所处的状态可分为以下三种:1.可达状态2.可恢复状态3.不可达状态。只有当对象处于不可达状态时,系统才会真正回收该对象所占的资源。
- 一个对象可以被:1.一个方法的局部变量引用2.其他类的类变量引用3.其他对象的实例变量引用。(对于情况2:只有当该类销毁时,对于情况3:只有当对象销毁时),该对象才会进入可恢复状态。
- 程序只能控制一个对象何时不能再被任何引用变量引用,决不能控制它何时被回收。
- 程序虽然无法精确控制垃圾回收的时机,但依然可以通知系统进行垃圾回收,但是系统何时进行垃圾回收是不确定的,但是大部分时候,通知总会有些效果。通知有以下两种方式:
System.gc();
Runtime.getRuntime.gc();
- 只有当系统进行垃圾回收时,才会调用finalize()方法。
- 软引用,系统内存充足时是不会回收软引用对象的,只有当系统内存不足是,会回收软引用对象,所以软引用时候用在对内存敏感的程序里。
- 弱引用和软引用类似,但弱引用的引用级别更低,对于只有弱引用的对象,当jvm运行时,不管内存是否充足,都将回收弱引用对象。
- 虚引用,完全类似于没有引用,对象甚至感觉不到它的存在,如果一个对象只有一个虚引用,那么它和没有引用的效果大致相同。虚引用主要用于跟踪对象被垃圾回收的状态,徐引用不能单独使用,虚引用必须和引用队列联合使用。
- 要使用这些特殊的引用类,就不能保留对对象的强引用。如果保留了对对象的强引用,就会浪费这些引用类所提供的任何好处。
- 虚引用无法直接获得所引用的对象。
AA aa = new AA();
ReferenceQueue referenceQueue = new ReferenceQueue();
PhantomReference a = new PhantomReference(aa, referenceQueue);
aa = null;//必须要把强引用赋为空
System.out.println(referenceQueue.poll());//输出null
//通知系统进行gc
System.gc();
System.runFinalization();
//执行上面两行代码后,系统会把虚引用加到引用队列中。
System.out.println(referenceQueue.poll() == a);//输出true
System.out.println(referenceQueue.poll());//输出null,引用队列刚刚已经弹出,所以已经没有引用存在了- 理解弱引用和虚引用,可以通过下面代码来理解:
AA aa = new AA();
WeakReference weakReference = new WeakReference(aa);
System.out.println("弱引用: " + weakReference.get());//弱引用: AA@677327b6
ReferenceQueue referenceQueue = new ReferenceQueue();
PhantomReference a = new PhantomReference(aa, referenceQueue);
aa = null;//必须要把强引用赋为空
System.out.println(referenceQueue.poll());//null
//通知系统进行gc
System.gc();
System.runFinalization();
//执行上面两行代码后,系统会把虚引用加到引用队列中。
Reference poll = referenceQueue.poll();
System.out.println(poll == a);//true
System.out.println(referenceQueue.poll());//null
System.out.println("弱引用: " + weakReference.get());//弱引用: null
39.软引用:只要jvm开始工作,软引用指向的对象就会被回收。
40. 虚引用:只要jvm开始工作,虚引用指向的对象就会被回收。系统还会被虚引用放入引用队列 ReferenceQueue
41. 当某个方法需要访问系统硬件,可以用native修饰该方法,再把该方法交给C实现。一旦Java程序包含了native方法,这个程序将失去跨平台的功能。
42. Java程序在不同操作系统上运行时,可能需要取得平台相关的属性,或者调用平台命令来完成特定功能。Java提供了System类和Runtime类来与程序的运行平台进行交换。
43. System类代表当前Java程序的运行平台。程序不能创建System类的对象。
44. System类提供了System.identityHashCode()方法,该方法返回指定对象的精确hashCode()值,也就是根据对象在内存中的地址所生成的hashCode值。当某个类的hashCode()被重写后,该类实例的hashCode()方法就不能唯一标识该对象,但是可以通过System.identityHashCode()方法的返回值来判断。结论:如果两个对象的identityHashCode值相等,那么他俩一定是同一个对象。
45. Runtime类的介绍参照《疯狂Java讲义》
46. 用utf-8使用中文就会占用3个字节,英文的话只有一个字节 如果是unicode则都是2个字节, gbk,一个汉字字符也是2个字节
47. Math的构造器是private,所以无法创建Math类的对象,Math中的所有方法都是类方法。
48. 数组中可以保存基本数据类型或对象,集合中只能保存对象。
49. null可以被强制类型转换成任意类型的对象
50. 方法的重写(override)两同两小一大原则:
方法名相同,参数类型相同
子类返回类型小于等于父类方法返回类型,
子类抛出异常小于等于父类方法抛出异常,
子类访问权限大于等于父类方法访问权限。
51. 本题主要考察String对象的不可变性。
toUpperCase()会对当前对象进行检查 如果不需要转换直接返回当前对象,否则new一个新对象返回;
参见如下代码:
String x="wmn";
String s = x.toLowerCase();
System.out.println(s==x);//true
String y=x.replace('f','F');
System.out.println(x==y);//true
- catch到异常后先执行finally块在执行catch中的return语句
Integer n3 = Integer.valueOf(47)
Integer n4 = Integer.valueOf(47);
这里的n3==n4才是true。
如果直接使用new一个对象,从构造函数来看:
public Integer(int value) {
this.value = value;
}
就是完全不同的两个对象,没有使用所谓的缓存。
以下是Java中的源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
i=i++
等效于
int temp = j;
j = j + 1;
j = temp;int j = 0;
这个表达式的输出是0 !!!
System.out.println(j++);-
i= i ++;
i++这个表达式的值为0,然后将i+1得到i=1
然后将上面i++这个值为0的表达式赋值给i
所以结果i=0 - 1.finally{}代码块比return先执行。
2.多个return是按顺序执行的的,多个return执行了一个后,后面的return就不会执行了。
3.记住一点,不管有不有异常抛出, finally都会在return返回前执行。
以上结论是自己在eclipse中编译测试过的,不正确之处请多多指教 - 程序先执行try块中return之前的代码(包括return语句中的表达式运算此时也要执行); 再执行finally块,最后执行try块中的return; 而 finally块之后的return语句,因为程序在try块中已经return了,所以不再执行。
- 记住:无论如何finally语句都要执行就会这个题了
finally语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句不能影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回。 - 快速失败(Fail-Fast)机制:对于线程不安全的集合对象的迭代器,如果在使用迭代器的过程中有其他线程修改了集合对象结构或者元素数量,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。
迭代 HashMap 采用快速失败机制,而 HashTable 不是,因为 HashTable 是线程安全的。 - A:HashMap和Hashtable两个类都实现了Map接口,二者保存K-V对(key-value对)
B:HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
C:Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
D:由所有HashMap类的“collection 视图方法”所返回的迭代器都是快速失败的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出ConcurrentModificationException。Hashtable和HashMap的区别主要是前者是同步的,后者是快速失败机制保证 `interface A{
} class B implements A{ } class C extends B{ }`
`
public class Iinstanceof {public static void main(String[] args) {
A ab=new B();
A ac=new C();
B bc=new C();
B bb=new B();
C cc=new C();
//对象实现一个接口,用这个对象和这个接口进行instanceof判断,都为true。
System.out.println(“ab instanceof A=”+(ab instanceof A));
System.out.println(“ac instanceof A=”+(ac instanceof A));
System.out.println(“bc instanceof A=”+(bc instanceof A));
System.out.println(“bb instanceof A=”+(bb instanceof A));
System.out.println(“cc instanceof A=”+(cc instanceof A));
//对象和父类进行instanceof判断,都为true
System.out.println(“ab instanceof B=”+(ab instanceof B));
System.out.println(“ac instanceof B=”+(ac instanceof B));
System.out.println(“bc instanceof B=”+(bc instanceof B));
System.out.println(“bb instanceof B=”+(bb instanceof B));
System.out.println(“cc instanceof B=”+(cc instanceof B));
//对象和他的子类进行instanceof判断为false
System.out.println(“ab instanceof C=”+(ab instanceof C));
System.out.println(“ac instanceof C=”+(ac instanceof C));
System.out.println(“bc instanceof C=”+(bc instanceof C));
System.out.println(“bb instanceof C=”+(bb instanceof C));
System.out.println(“cc instanceof C=”+(cc instanceof C));
}
}`
程序输出:
ab instanceof A=true
ac instanceof A=true
bc instanceof A=true
bb instanceof A=true
cc instanceof A=true
ab instanceof B=true
ac instanceof B=true
bc instanceof B=true
bb instanceof B=true
cc instanceof B=true
ab instanceof C=false
ac instanceof C=true
bc instanceof C=true
bb instanceof C=false
cc instanceof C=true
对于多态的情况,instanceof 看的是=右边的对象的继承关系,而不是左边。- 静态块:用static申明,JVM加载类时执行,仅执行一次,且按声明顺序执行
构造块:类中直接用{}定义,每一次创建对象时执行
执行顺序优先级:静态块>main()>构造块>构造方法 - 1) 首先初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化
2) 然后初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化
3) 其次初始化父类的普通成员变量和代码块,再执行父类的构造方法
4) 最后初始化子类的普通成员变量和代码块,再执行子类的构造方法
对象初始化时,先给对象的属性赋默认值,然后调用构造方法 - ceil:天花板,即向上取整。
floor:地板,即向下取整。
值得一提的是:二者返回的都是浮点型。
至于为什么是-0.0,而不是0.0,因为源码注释:“If the argument value is less than zero but greater than -1.0, then the result is negative zero ”,翻译过来就是:如果参数是-1.0到0.0之间的数,结果是-0.0。 - java常量池不在堆中也不在栈中,是独立的内存空间管理。
1. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
2. 堆:存放所有new出来的对象。
3. 常量池:存放字符串常量和基本类型常量(public static final)。
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。 public static int methodB() {
int aa=3;
try {
return aa++;
} catch (Exception e) {} finally { return aa; }
}
输出结果是4- 一般不要使用finalize,最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++),finalize()的工作就是回收这部分的内存。
- linkedList、ArrayList都不是线程安全的,Vector是线程安全的,但是效率很低,现在很少用
Hashtable和Hasnmap功能差不多,但Hashtables是线程安全的 - 集合中线程安全的类有:vector,stack,hashtable,enumeration,除此之外均是非线程安全的类与接口
- java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。 - Java反射中,getDeclaredMethods()可以拿到当前类的所有方法和直接的继承类、接口的public方法。
- getMethods()可以拿到当前类的public方法和继承类、接口的public方法。(只能拿到public方法!!)
- Vector支持线程同步,其实现原理是在方法中加入关键字synchronized从而在线程A访问A方法时线程B等待,但在并发下影响效率所以引入ArrayList,其方法中不加锁,牺牲安全性换来效率。
- Vector & ArrayList 的主要区别
1) 同步性:Vector是线程安全的,也就是说是同步的 ,而ArrayList 是线程序不安全的,不是同步的 数2。
2)数据增长:当需要增长时,Vector默认增长为原来一倍 ,而ArrayList却是原来的50% ,这样,ArrayList就有利于节约内存空间。
如果涉及到堆栈,队列等操作,应该考虑用Vector,如果需要快速随机访问元素,应该使用ArrayList 。
扩展知识:
1. Hashtable & HashMap
Hashtable和HashMap它们的性能方面的比较类似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
83. 在java语言中虚函数指代的就是抽象方法,抽象方法中不能用private,static, synchronized,native等修饰词修饰。
84. 其实 普通的类方法是可以和类名同名的,和构造方法唯一的区分就是,构造方法没有返回值。
85. 当实例化子类对象时,首先要加载父类的class文件进内存,静态代码块是随着类的创建而执行,所以父类静态代码块最先被执行,子类class文件再被加载,同理静态代码块被先执行;实例化子类对象要先调用父类的构造方法,而调用父类构造方法前会先执行父类的非静态代码块
86. 1.this 和 super 只能放在第一行
2.this()和super()不可以同时出现在一个构造函数中
3.在方法中定义使用的this关键字,它的值是 当前对象 的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.
this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.
87. JAVA没有指针的概念,被封装起来了,而C++有;JAVA不支持类的多继承,但支持接口多继承,C++支持类的多继承;C++支持操作符重载,JAVA不支持;JAVA的内存管理比C++方便,而且错误处理也比较好;C++的速度比JAVA快。
C++更适用于有运行效率要求的情况,JAVA适用于效率要求不高,但维护性要好的情况。
88. JAVA不使用指针,不支持头文件,不支持宏定义,JAVA可以动态分配内存
C++比较适合一些底层处理,JAVA比较适合开发应用,可以是WEB,也可以是手机端的Android。
89. finally块的语句在try或catch中的return语句 执行之后 返回之前 执行且finally里的修改语句可能影响也可能不影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回。
90. 有关hashMap跟hashTable的区别 http://www.nowcoder.com/test/question/done?tid=3894394&qid=14454#summary
91. 综上所述,接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:
行为模型应该总是通过接口而不是抽象类定义。所以通常是:优先选用接口,尽量少用抽象类。
选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供共性的功能。
92. 面向对象的五大基本原则
s( Single-Resposibility Principle ): 单一职责原则
o( Open-Closed principle ): 开放封闭原则
l( Liskov-Substituion Principle ): 里氏原则
i( Interface-Segregation Principle ): 接口隔离原则
d( Dependecy-Inversion Principle ): 依赖倒置原则
一个单词:立方体(solid),很好记!!!
93. 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,其他的都是非线程安全的类和接口。
94. class A {}
class B extends A {}
class C extends A {}
class D extends B {}
耐心看完,保证能懂这道题!
1. 只看尖括号里边的!!明确点和范围两个概念
2. 如果尖括号里的是一个类,那么尖括号里的就是一个点,比如List《A》,List《B》,List《Object》
3. 如果尖括号里面带有问号,那么代表一个范围,《? extends A>》代表小于等于A的范围,《? super A》代表大于等于A的范围,《?》代表全部范围
4. 尖括号里的所有点之间互相赋值都是错,除非是俩相同的点
5. 尖括号小范围赋值给大范围,对!大范围赋值给小范围,错!如果某点包含在某个范围里,那么可以赋值,否则,不能赋值
6. List《?》和List 是相等的,都代表最大范围
public static void main(String[] args) {
List<A> a;
List list;
list = a; //A对,因为List就是List<?>,代表最大的范围,A只是其中的一个点,肯定被包含在内
List<B> b;
a = b; //B错,点之间不能相互赋值
List<?> qm;
List<Object> o;
qm = o; //C对,List<?>代表最大的范围,List<Object>只是一个点,肯定被包含在内
List<D> d;
List<? extends B> downB;
downB = d; //D对,List<? extends B>代表小于等于B的范围,List<D>是一个点,在其中
List<?extends A> downA;
a = downA; //E错,范围不能赋值给点
a = o; //F错,List<Object>只是一个点
downA = downB; //G对,小于等于A的范围包含小于等于B的范围,因为B本来就比A小,B时A的子类嘛
}
- static方法,是属于这个类的,不是属于对象的。
没有继承不继承的说法。覆盖和重写也是说的对象的方法而不是static方法。 - http://www.nowcoder.com/test/question/done?tid=3896795&qid=36455#summary Java异常的讨论。
- 如果不需要内部类对象与其外部类对象之间有联系,那么可以将内部类声明为static,对于这种说法,我尝试着在A包下面建了一个类X,并在其内部声明了一个静态内部类Y(也叫嵌套类),然后同样是在A包下面,我新建了一个类B,然后在这个类中引用前面那个类Y,发现可以直接引用,说明X与Y的确没有联系(虽然引用的时候需要用X.Y的方式引用,不过貌似好像就这点联系了。)如果Y没有声明为static,那么是无法在B中引用Y的。其实说了这么多,总结来讲,就是static的作用是相当于建立了2个类,而不是你所讲的,这个有static修饰的类先加载。我们也可以看到,在工作目录下的确也是生成了2个class文件,既然是2个类,那么这两个类的关系就是单纯的继承关系了
- 父类构造器调用重写的方法的典型例题http://www.nowcoder.com/test/question/done?tid=3897868&qid=3212#summary
- `
public class Enclosingone {
//非静态内部类
public class InsideOne {}
//静态内部类
public static class InsideTwo{}
}
class Mytest02{
public static void main(String args []){
Enclosingone.InsideOne obj1 = new Enclosingone().new InsideOne();//非静态内部类对象
Enclosingone.InsideTwo obj2 = new Enclosingone.InsideTwo();//静态内部类对象
}
}`
100. C,java不完全算是编译型语言,他编译的字节码文件运行时是解释执行的,其次,java和C++的类也不都完全是静态绑定的,比如C+++的虚函数,java的父类引用子类对象等情况。
D,java也可以数组溢出,溢出是会抛出异常,也就是ArrayIndexOutOfBoundsException
101. “ 接口中可以包含静态方法 ”,jdk1.8中可以有,而jdk1.7编译错误