2016-10-19 html
初级问题,可是仍是加入了笔记,由于得满分不容易。 &和&&均可以用做逻辑与的运算(两边是boolean类型),全真则真,一假则假。 &&还具备短路的功能,即第一个表达式为false,则再也不计算第二个表达式。例如, if(str != null&& !str.equals(““)) 当str为null时,后面的表达式不会执行,不会出现NullPointerException,若是将&&改成&,则会抛出NullPointerException异常。 &还能够用做位运算符,当&操做符两边的表达式不是boolean类型时,&表示按位与操做,咱们一般使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。备注:这道题先说二者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来代表本身理解透彻深刻。
前半部分是老生常谈的。你们都知道:final 用于声明类的属性,方法和类自己,分别表示属性自己不可变,方法不可覆盖,类不可继承。且内部类要访问局部变量,局部变量必须定义成final类型,由于常量的做用范围变大,内部类才能够访问到。java
本题问的主要是后者,涉及到了Java内存模型和重排序的含义。更加详细参考下面文章c++
简单说就是构造器内对一个final域的写,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操做之间不能重排序,即若是final域在构造器内初始化,那么必定是先初始化完毕,才能使用对象。不会逃逸。程序员
初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操做之间不能重排序,读final域的重排序规则能够确保:在读一个对象的final域以前,必定会先读包含这个final域的对象的引用。面试
在构造器内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操做之间不能重排序。算法
不能执行,编译有错, final修饰的变量是常量,使用以前必须进行初始化,能够显示初始化,也能够经过构造方法或者初始化块进行初始化,若是不初始化编译会报错。
finalize是Object类的一个保护方法 protected void finalize() throws Throwable { } 当垃圾回收器肯定不存在对该对象的更多引用时,对象的垃圾回收器自动调用此方法,程序员能够覆盖此方法提供垃圾收集时的其余资源回收,例如关闭文件等。而记得《Java编程思想》说:“若是须要进行清理,最好是编写你本身的清理方法,但不要用finalize”,其实你写了或者你用了“本身的清理方法”,只是没感受到。好比I/O的close方法就是,如今的问题是为何释放资源的代码不直接写在finalize里面。由于手动调用它,JVM不保证此方法总被及时调用或者根本不保证会被调用,这都不能保证,要你何用。并且它的调用对性能影响很大。具体来讲就是: java的GC只负责内存的清理,全部其它资源的清理必须由程序员手工完成。要否则会引发资源泄露,有可能致使程序崩溃。 而finalize()是Object的protected方法,那么子类理论上能够覆盖该方法,且GC会在回收对象以前调用对象的该方法。可是finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是肯定的(对象离开做用域或delete掉),但Java中的finalize的调用具备不肯定性,不建议用finalize方法完成“非内存资源”的清理工做。Java语言规范并不保证finalize方法会被及时地执行、并且根本不会保证它们会被执行,finalize方法可能会带来性能问题。由于JVM一般在单独的低优先级线程中完成finalize的执行。 在Java虚拟机的垃圾回收器看来,堆区中的每一个对象均可能处于如下三个状态之一。 可触及状态:当一个对象(假定为Sample对象)被建立后,只要程序中还有引用变量引用它,那么它就始终处于可触及状态。 可复活状态:当程序再也不有任何引用变量引用Sample对象时,它就进入可复活状态。在这个状态中,垃圾回收器会准备释放它占用的内存,在释放以前,会调用它及其余处于可复活状态的对象的finalize()方法,这些finalize()方法有可能使Sample 对象从新转到可触及状态。 不可触及状态:当Java虚拟机执行完全部可复活对象的finalize()方法后,假如这些方法都没有使Sample对象转到可触及状态,那么Sample对象就进入不可触及状态。只有当对象处于不可触及状态时,垃圾回收器才会真正回收它占用的内存。 一个对象开始是可触及态的,当对象到GC Root没有任何引用链接相连。那么就证实这个对象目前是不可用的,这时这个对象就被判死缓了(从可触及到可复活),可是想要真正的对这个对象判死刑,这个对象还至少经历两次判决。第一次是判断是否有必要对这个对象执行finalize()方法,若是当前对象没有覆盖finalize()方法,或finalize()方法已经被调用过了(最多调用一次),那么当前对象就不会调用finalize()方法了,即对象成功的逃脱了一审判决。若是对象有必要执行finalize()方法,那么这个对象会被放入一个叫作F-Queue的队列中,这也就意味着在一审中这个对象已经被判死刑了,可是还没执行。而在JVM中,会有一个叫作Finalizer的低优先级线程去触发可复活对象的finalize()方法,finalize()方法是对象逃脱死刑的最后一次机会,若是在finalize()的过程当中成功的与GC Root相连,则对象成功的逃脱死刑(进入可触及态)。不然对象就会被第二次标记(进入不可触及态),被第二次标记的对象就会被送上刑场枪毙。又想起一个问题,即便在程序里,不显式指定对象指向null,JVM也会找机会解决它。 分析说明:finalize方法至多由GC执行一次, 尽管finalize()方法是保证在回收内存空间以前执行的,可是对具体的执行时间和执行顺序是没有任何保证的。多个实例之间的finalize()执行顺序是不能提早预知的,甚至有可能它们是并行执行的。程序不该该预先假设实例执行finalize()的方法,也不该该使用finalize()方法来回收资源。
这个题很重要,纠正我一个误区:Java只有值传递。java中没有显式的指针。没有相似c和c++的那种地址,引用传递。对于java值传递,形参str指向了实参str指向的对象good字符串,可是change方法内部,形参str指向从新开辟一个空间存储的test ok,change执行完毕,实参str的指向对象并无被修改。故不起做用。而ch是数组,值传递的是对象的引用,值发生了改变,打印good and gbc
重要:别混淆:Java传参方式只有一种:按值传递
Java一直是只有值传递。不幸的是,制定规则的人决定把Java里的指针的东西叫作引用,所以初学者老是被搞晕。其实这些引用也是经过值传递的。即Java中传递任何东西都是传值。若是传入方法的是基本类型的东西,你就获得此基本类型的一份拷贝。若是是传递引用,就获得引用的拷贝。 通常来讲,对于基本类型的传递,咱们很容易理解,而对于对象,总让人感受是按引用传递。
1true 编程
取得类的全部方法的对象。 public Method[] getDeclaredMethods() //返回类或接口声明的全部方法,包括public, protected, default (package) 访问和private方法的Method对象,但不包括继承的方法。固然也包括它所实现接口的方法。 public Method[] getMethods() // 返回某个类的全部public方法,包括其继承类的公用方法,固然也包括它所实现接口的方法 Java反射 能够理解为在运行时期获取对象类型信息的操做,传统的编程方法要求程序员在编译阶段决定使用的类型,可是在反射的帮助下,编程人员能够动态获取这些信息,从而编写更加具备可移植性的代码。严格地说,反射并不是java语言的特性,由于任何一种语言均可以实现反射机制,可是若是编程语言自己支持反射,那么反射的实现就会方便不少。 得到类型类;Java中一切都是对象,咱们通常所使用的对象都直接或间接继承自Object类。Object类中包含一个方法名叫getClass(final修饰),利用这个方法就能够得到一个实例的类型类。类型类指的是表明一个类型的类,由于一切皆是对象,类型也不例外,在Java使用类型类来表示一个类型。全部的类型类都是Class类的实例。例: A a = new A(); if(a.getClass()==A.class) System.out.println("equal"); else System.out.println("unequal"); 结果就是打印出 “equal”。对象a是A的一个实例,if中使用a.getClass()返回的结果正是A的类型类。在Java中表示一个特定类型的类型类能够用“类型.class”的方式得到,由于a.getClass()得到是A的类型类,也就是A.class,所以上面的代码执行的结果就是打印出 “equal”,特别注意的是,类型类是一一对应的,父类的类型类和子类的类型类是不一样的,所以,假设A是B的子类,那么以下的代码将获得 “unequal”的输出: A a = new A(); if(a.getClass()==B.class) System.out.println("equal"); else System.out.println("unequal"); 所以,若是你知道一个实例,那么你能够经过实例的“getClass()”方法得到该对象的类型类,若是你知道一个类型,那么你可使用“.class”的方法得到该类型的类型类。 小结: Class cl=A.class; // JVM将使用类A的类装载器, 将类A装入内存(前提是:类A尚未装入内存),不对类A作类的初始化工做.返回类A的Class的对象(类型类,一切都是对象)。 Class cl=对象引用.getClass(); // 返回引用运行时真正所指的对象(由于:子对象的引用可能会赋给父对象的引用变量)所属的类的Class的对象。 Class.forName(); // 返回的是一个类, .newInstance() 后才建立一个对象, Class.forName()的做用是要求JVM查找并加载指定的类 得到类型的信息 在得到类型类以后能够调用其中的一些方法得到类型的信息,主要的方法有: getName():String:得到该类型的全称名称。 getSuperClass():Class:得到该类型的直接父类,若是该类型没有直接父类,那么返回null。 getInterfaces():Class[]:得到该类型实现的全部接口。 isArray():boolean:判断该类型是不是数组。 isEnum():boolean:判断该类型是不是枚举类型。 isInterface():boolean:判断该类型是不是接口。 isPrimitive():boolean:判断该类型是不是基本类型,便是否是int,boolean,double等等。 isAssignableFrom(Class cls):boolean:判断这个类型是不是类型cls的父(祖先)类或父(祖先)接口。 getComponentType():Class:若是该类型是一个数组,那么返回该数组的组件类型。
Object的getClass做用是返回运行时的类的名字,可是SuperTest和Date的getClass都没有被重写,他们都是调用Object的getClass,而Object的getClass做用是返回运行时的类的名字。那么此时这个运行时的类就是当前类,因此返回的是test.SuperTest,与Date类无关,要返回Date类的名字须要写super.getClass().getSuperclass()。还有别忘了包名!
java的访问权限有public、protected、private和default的,default不能修饰变量。native是方法修饰符。定义navtive方法时,并不提供实现体,由于其实现体是用非Java语言在外面实现的。native能够和任何修饰符连用,abstract除外。由于native暗示这个方法有实现体,而abstract却显式指明了这个方法没有实现体。
从c++/c的角度来看,数组的复制就是对某块内存的复制,直接和内存打交道的是最快的,for循环的话,for是最慢的。虽然很灵活。 看System.arraycopy()源码: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 能够看到是native方法:native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其余语言(如C和C++)实现的文件中。 能够将native方法比做Java程序同C程序的接口。效率最高。 C项写法就错了,copyOf不是System的方法,而是Arrays的静态方法,下面是源码,能够看到本质上是调用的本地方法arraycopy,那么其效率必然是比不上 arraycopy的。 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } clone的话,属于Object类的保护本地方法,返回的是Object,须要强制转换。 通常用clone效率是比较差的。 protected native Object clone() throws CloneNotSupportedException;
main()方法必定是静态的。若是main()容许是非静态的,那么在调用main方法时,JVM就得实例化它的类。在实例化时,得调用类的构造函数。必然要找该类的入口,而入口是非静态的方法,矛盾了。main()方法必须声明为静态的,这样JVM才能够调用main()方法而无需实例化它的类。若是从main()方法去掉“static”这个声明,虽然编译依然能够成功,但在运行时会致使程序失败。 对于后个问题,固然能够重载main()方法。一个Java类能够有任意数量的main()方法。为了运行java类,类的main()方法应该有例如“public static void main(String[] args)”的声明。若是对此声明作任何修改,编译也是能够成功的。可是,运行不了Java程序。会获得运行时错误,由于找不到main方法。
不能,main方法必须public。不能定义main()方法为private和protected,也不能不用访问修饰符。这是为了能让JVM访问main()方法。若是你不定义main()方法为public,虽然编译也会成功,但你会获得运行时错误,由于找不到main方法。
不能,由于main方法是静态方法,而在Java中静态方法在编译时会结合在一块儿,因此你在Java中不能覆盖静态方法。
main方法能够在Java中同步,synchronized修饰符容许用于main方法的声明中,这样就能够在Java中同步main方法了。
java.lang包在使用的时候无需显示导入,编译时由编译器自动导入。提供java编成语言的程序设计的基础类.Object类是类层次结构的根,Java中全部的类从根本上都继承自这个类。Object类是Java中惟一没有父类的类。其余全部的类,包括标准容器类,好比数组,都继承Object类中的方法 补充;Object类源代码分析 package java.lang; public class Object { /* 一个私有静态的native方法,具体是用C(C++)在DLL Dynamic Link Library 中实现的,而后经过JNI调用。*/ private static native void registerNatives(); /* 对象初始化时自动调用此方法*/ static { registerNatives(); } /* 返回此 Object 的运行时类。*/ public final native Class<?> getClass(); /* hashCode 的常规协定是: 1.在 Java 应用程序执行期间,在对同一对象屡次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另外一次执行,该整数无需保持一致。 2.若是根据 equals() 方法,两个对象是相等的,那么对这两个对象中的每一个对象调用 hashCode 方法都必须生成相同的整数结果。3.若是根据 equals() 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求必定生成不一样的整数结果。可是,程序员应该意识到,为不相等的对象生成不一样整数结果能够提升哈希表的性能。*/ public native int hashCode(); //Object类的equals()方法判断调用equals()方法的引用于传进来的引用是否一致,即两个引用是否指向同一个对象。Object类中的equals()方法等价于==。 //只有当继承Object的类覆写(override)equals()方法以后,继承类实现equals(),才能够说equals()方法与==的不一样。 //equals()方法须要具备以下特色: //自反性(reflexive):任何非空引用x.equals(x)返回为true。 //对称性(symmetric)任何非空引用x和y,x.equals(y)返回true当且仅当y.equals(x)返回true。 //传递性(transitive):任何非空引用x和y,若是x.equals(y)返回true,而且y.equals(z)返回true,那么x.equals(z)返回true。 //一致性(consistent):两个非空引用x和y,x.equals(y)的屡次调用应该保持一致的结果,(前提条件是在屡次比较之间没有修改x和y用于比较的相关信息)。 //约定:对于任何非空引用x,x.equals(null)应该返回为false。而且覆写equals()方法时,应该同时覆写hashCode()方法,反之亦然。 public boolean equals(Object obj) { return (this == obj); } /*本地clone方法,用于对象的复制。(想到了一个面试题:Java生成对象有几种方式?)任何类在实例上调用clone(),他将实现cloneable接口重写clone方法建立副本。有这个方法的类必须实现java.lang.Cloneable接口,不然会抛出CloneNotSupportedException异常。Cloneable接口中不包含任何方法,因此实现它时只要在类声明中加上implements语句便可。 第二个比较特殊的地方在于这个方法是protected修饰的,覆写clone()方法的时候须要写成public,才能让类外部的代码调用。 protected native Object clone() throws CloneNotSupportedException; /*返回该对象的字符串表示。打印引用会自动调用对象的toString()方法,打印出引用所指的对象的toString()方法的返回值,由于每一个类都直接或间接地继承自Object,所以每一个类都有toString()方法。 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public final native void notify(); public final native void notifyAll(); /*在其余线程调用此对象的 notify() 方法或 notifyAll() 方法前,致使当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用同样。当前线程必须拥有此对象监视器。该线程发布对此监视器的全部权并等待,直到其余线程经过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。而后该线程将等到从新得到对监视器的全部权后才能继续执行。*/ public final void wait() throws InterruptedException { wait(0); } /*在其余线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,致使当前线程等待。*/ public final native void wait(long timeout) throws InterruptedException; /* 在其余线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其余某个线程中断当前线程,或者已超过某个实际时间量前,致使当前线程等待。*/ public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { timeout++; } wait(timeout); } /*当垃圾回收器肯定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 protected void finalize() throws Throwable { } }
枚举类全部的枚举值都是类静态常量,在初始化时会对全部的枚举值对象进行第一次初始化。枚举类在后台实现时,其实是转化为一个继承了java.lang.Enum类的实体类,原先的枚举类型变成对应的实体类型,上例中AccountType变成了个class AccountType,而且会生成一个新的构造函数,若原来有构造函数,则在此基础上添加两个参数,生成新的构造函数,新构造器会包含已有的构造器的代码,并且在这个类中,还会添加若干(本例子是3个字段)静态final字段来表明具体的枚举类型。最后并且还会添加一段static代码段初始化他们。在初始化过程当中new AccountType构造函数被调用了三次,因此Enum中定义的构造函数中的打印代码被执行了3遍。或者简单的说private类内可见,类外不可见,枚举类有三个实例,故调用三次构造方法,打印三次It is a account type,而后main方法里打印一次FIXED。
java 中的instanceof 运算符是用来在运行时指出对象是不是特定类的一个实例。instanceof经过返回一个布尔值来指出这个对象是不是这个特定类或者是它的子类的一个实例。 用法: result = object instanceof class 参数: Result:布尔类型。 Object:必选项。任意对象表达式。 Class:必选项。任意已定义的对象类。 说明:若是 object 是 class 的一个实例,则 instanceof 运算符返回 true。若是 object 不是指定类的一个实例,或者 object 是 null,则返回 false。 至于具体实现原理,简单说说:JVM有一条名为 instanceof 的指令,而Java源码编译到Class文件时会把Java语言中的 instanceof 运算符映射到JVM的 instanceof 指令上。
参考:Java instanceof 关键字是如何实现的? 数组
super(), this() 都得放在构造函数第一行,确定不能放在一块儿。编程语言
super表明父类对应的对象,因此用super访问在子类中没法直接使用的父类成员和方法,若是在子类中对从父类继承来的成员变量进行从新定义,即出现了子类变量对父类变量的隐藏,不是说的private成员。ide
public class Outter{ public class Inner{ } } 内部类就不须要与文件名相同
形式参数就是函数定义时设定的参数。例如函数头 int min(int x,int y,int z) 中 x,y,z 就是形参。 实际参数是调用函数时所使用的实际的参数。 形参能够是对象,是对象的时候传递引用.形式参数只能用final修饰符,其它任何修饰符都会引发编译器错误 。可是用这个修饰符也有必定的限制,就是在方法中不能对参数作任何修改。 不过通常状况下,一个方法的形参不用final修饰。只有在特殊状况下,那就是:方法内部类。 一个方法内的内部类若是使用了这个方法的参数或者局部变量的话,这个参数或局部变量应该是final。 形式参数可被视为local variable。形参和局部变量同样都不能离开方法。都只有在方法内才会发生做用,也只有在方法中使用,不会在方法外可见。
a选项 -d便可设置系统属性 c选项 一次编译多个java文件用javac *.java. 便可编译当前目录下的全部java文件 d选项 -s指定存放生成的源文件的位置