目录
前言:
在大部分的笔试题中,都会有一部分选择题,而这部分选择题中其实也是对整个系统知识的考验,其很多的细节问题难度不比一些算法题容易(因为这些细节可能是平常写代码都没碰到过的场景,所以在不了解的情况下就只能靠感觉去猜了)。本篇将从这1000道左右的题中进行规律总结与相关知识整备。
题库来源:牛客网
一、Java中的各种类的权限
对于类的权限的考点,就是常见的问外部类、内部类等,能否用一些权限修饰符修饰(public、privated等)。
知识总结:
首先需要了解Java的几种类:
外部类:就是我们经常先定义的一个类,也就是最外层的类
成员内部类:顾名思义,就是外部类的一个成员,那么和外部类的其他方法以及属性是并列的,那么成员内部类和外部类的方法一样的话,那么就同样可以有public、protected、private修饰 。并且可以无限制的访问外部类的各种属性与方法,包括私有的。但是成员内部类不能有任何的static的变量和方法。
// 外部类的方法
public void outerDisplay(){
System.out.println("outerClass...");
}
//成员内部类
public class InnerClass{
public void innerDisplay(){
//使用外部类的属性
str = "chenssy...";
System.out.println(str);
//使用外部类的方法
outerDisplay();
}
}
局部内部类:同样顾名思义,和局部变量(方法里面定义的变量)的效果类似,只能在方法或者作用域中定义的类,局部内部类只能在该方法中使用,出了方法就失效。那么与局部变量类似,就没有权限修饰符这一说法了,所以就不能够使用private、protected、public等访问修饰说明符修饰,也不能使用static修饰。
//定义在方法中:
public class Parcel5 {
//成员方法
public Destionation destionation(String str){
//方法中的内部类:局部内部类
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
}
静态内部类:可以看做是一个静态的成员内部类(用static修饰的),那么规则和成员内部类类似,可以有修饰符public、protected、private修饰,但需要注意的是静态的只能访问静态的,不能访问非静态的。
/**
*静态内部类
*/
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _name1 = "chenssy_static";
public void display(){
/*
* 静态内部类只能访问外部类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + name);
}
}
/**
* 非静态内部类
*/
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _name2 = "chenssy_inner";
/* 非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + name);
}
}
匿名内部类:同样可以顾名思义,没有名字的内部类,其使用的目的一般是想创建一个类的实力,但是又只需要用一次,或者说定义类的同时并创建这个类,匿名内部类可以参考局部内部类,一般也是在写在方法里面,同样没有任何的修饰符,并且不能存在任何的静态变量和方法。使用的时候直接就是new 匿名内部类();
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}
这种就是最基本的4个访问权限的概念public protected default private,很多同学可能会忘记protected和default的权限区别。
权限等级顺序如下:
public:最高权限,公有;
protected:受保护,可以允许包内以及子类访问(可以是外部包的子类所以因为这点要比default权限大);
default:只允许包内访问;
private:私有,只允许本类进行访问,权限最小。
类型二:
类的各种成员访问权限问题,以及名字叫法区别(有点无语)
这题的关键可能就是对于概念的描述弄清楚就很简单,但这题看似简单但对于没有听说过类方法的就容易混淆,到底是指类的成员方法,还是指静态方法。
总结
成员方法又叫实例方法
静态方法又叫类方法
知道实际的叫法那么就很好解决了
A.在静态方法中可以用this调用本类的静态方法; static修饰的方法中不允许使用this, 错误
B.在静态方法中调用本类静态方法可以直接调用; static可以直接调用static方法 正确
C.在静态方法中只能调用本类的静态方法; 别的类的非私有可以调用,此处描述过于绝对 错误
D.在静态方法中绝对不能调用成员方法; 参考main方法怎么调用成员方法(new对象即可) 错误
二、字符串拼接问题
首先就是小括号的优先级是最高的,所以就会变成x+y+""+25+y;
这里需要注意的就是字符串相加的顺序,字符串前面的按原来的格式加,后面的都按字符串的格式加。所以“”前面的x+y按原格式相加为25,后面的25+y会变成字符串的格式拼接。所以就变成了25255。
三、垃圾回收机制
了解过Java的都知道,Java有独特的垃圾回收机制来管理内存,当需要回收的时候会通过GC线程来进行回收,但是回收的时间顺序不是外部可以控制的,所以并不能够定义垃圾回收的时间和顺序,而程序员只能够通过System.gc()来建议执行垃圾回收,但具体的回收时间,是不可知的。
四、Java中的类型转换问题
在Java中有八大基本数据类型:byte short char int long flot double boolean,其中默认的整数类型是int,默认的小数类型是double。而再java中会经常出现一些类型转换的问题(有意和无意的)。所以需要了解Java的类型转换机制。
Java类型转换机制:
当需要类型转换时Java会默认将小类型的转换成大类型的,而大类型的不能转换成小类型的(只能自己强制转换)。也就是小范围可以赋值给大范围的类型,而大范围的要强制转换才能正确赋值,并且这种情况会出现精度丢失问题。
自动转换顺序如下:
byte->short->char->int->long->float->double
比如当我们定义double d=1这样是可以的,但是不能定义int i=7.6;
题2
本题也是考察的经典基本类型转换的问题,如果你知道小类型可以转换成大类型,而大类型不能转换成小类型(需要手动强转)
fun1是因为return没有返回值错误.
fun2是将short类型转换成float类型,小类型转大类型,正确
fun3是将long转为float类型,无强制转换,因为float要比long大。
fun4和fun3同理,double转float,错误,double比float大。
题3
在Java中,byte,short,char在运算的时候都会升为int类型,所以b3、b8、b7的赋值语句中都出现了运算,也就是将一个int值赋值给byte,大类型转换小类型需要强制转换,所以这几个赋值都是错误,但为什么b6的赋值语句就没有错呢?同样也是用了+运算符,因为b4和b5都是被final修饰的常量,final修饰后的byte不会进行类型转换,所以b6得到的还是一个byte类型.
在IDEA中可以复刻。
题4
这题同样是有关类型转换的问题.
A选项和上题一样,byte类型进行+运算后为int类型,需要手动强制转换才能正确赋值;
B选项一样;
CD选项的区别就是使用的是+=,而不是AB选项的+,那为什么+=就可以而直接+就不行呢?
这是因为+=会进行自动强转,而使用+就需要手动的进行强制转换
同样以题3的例子也可以看到+=的不会报错,而+就会产生报错
五、多线程机制
类型一:
多线程题中最常见的就是关于start()方法和run()方法的区别。
当我们新建一个线程后,调用start()方法是让这个线程到了就绪状态,当分到时间片之后,就可以运行。
而run方法只是执行一遍线程的方法体,并且只有start()方法才是真正意义上的创建一个新的线程,而我们在main方法里面调用另一个线程的run方法时,此时只相当于main主线程的顺序执行,并没有创建一个新的线程。
所以上述题目的答案就是pongping,因为只是调用run()方法执行。如果是start()方法,就是两者都有可能。
类型二:线程中断
抛出InteruptedException的常见的方法有:
Objetc类的wait方法
Threed.sleep方法
Thread.join方法
六、变量的各种访问权限
这类问题最主要的就是有关一些类变量的访问。
总结:
静态变量:也就是static修饰的变量。在外部访问时,是直接可以通过类名.变量名访问,当然也可以通过类的实例对象.变量进行访问,只不过一般是直接类名.变量访问,但知道两者都可以就行。
私有变量:私有变量也就是private修饰的变量,在外部类是不能访问到的,但是在本类是可以访问到的,所以在本类的main方法中,使用实例对象.类名是可以访问到的.
注意有关b选项的this,this指针的作用也是相当于当前类的对象的一个指针,也就是上述图中的t的作用一样,但是static方法中是没有this的,所以在main方法中不能使用this指针。
七、Math包的各种方法
round():向上取整,可以理解为+0.5,然后向下取整数。Math.round(11.5) 11.5+0.5=12 所以答案为12
ceil():向上取整
floor():向下取整
需要注意的是会保留原本符号,符号不变,类型不变。
八、接口和抽象类的各种知识相关
题一
接口只能够继承接口,因为如果接口继承普通类的话,那么也继承了父类的成员变量,但接口里面只能有抽象方法或者是静态常量,这样就起冲突了,所以接口只能继承接口,B对。
💡只有接口可以多继承,其他的都是单继承。注意因为大家都知道java是单继承的,所以可能误以为接口也只能单继承!C对
类不管有没有些构造函数,java都会提供一个默认的无参构造函数,并且创建子类对象的时候,会先调用父类的构造函数。
题二
A.正确
B.因为final修饰的类不能够被继承,所以abstract也就没有意义,正确
C.正确
D.这里大家可能结合自己平常的开发的习惯,比如定义一个接口然后实现后就必须实现接口中的所有方法,但是在抽象类中,子类也可以声明为abstract,然后可以让子类的子类去实现,并不一定需要子类实现,所以描述中的必须导致该选项错误。
题三
对于这类题也是可能大家平常没有注意的细节,因为不管是抽象类还是接口大家在编写的时候一般都会手动的写出public,导致可能没有考虑不写权限修饰符的默认是什么。
抽象类:
JDK1.8之前:默认权限为protected
JDK1.8之后:默认权限为default
接口:
JDK1.8之前:接口中的方法必须为public
JDK1.8:可以是public,也可以是default
题四
抽象类可以有构造方法,但是不能够实例化,接口不能有构造方法。
抽象类中可以有自己的变量,接口只能有静态常量(默认就是public static final的);
抽象类和接口都可以有静态方法;
扩展:
JDK1.8后,可以拥有default方法,默认的方法是public abstract的
九、Java的相关命令
假设有一个我们编写了一个类Study。
首先就是通过编译命令:javac + 程序名字 也就是javac Study.java。 然后将这个类编译成字节码,这时候会生成一个Study.class文件.
当jvm需要运行的时候就是直接输入这个文件名即可(不需要后缀):java Study
所以A错误,因为多了个.class后缀.
十、基本类型和包装类型的问题
类型一:比较问题
在JAVA中,8大基本类型都有对应的包装类,这点要注意,包装类都是大写首字母开头,不细心的有时候会经常看错。而包装类有一个拆箱与装箱的操作。
拆箱就是包装类会拆箱成为基本类进行操作。
而装箱就是将基本类型变成对应的包装类对象进行操作。
1、基本类和封装类进行“==”操作:
这种情况包装类型会自动拆箱成基本类型进行比较。int i=1 Integer ig=new integer(1); i==ig 为true。
2、两个Integer对象进行“==”比较:
这个要单独拎出来就是因为有特殊机制,一般情况下整型变量是用的最多的,而Integer对象在-128到127这个范围内会将数据进行缓存,也就是当值在这个范围内时,==比较的结果为true,不在这个范围时结果为flase。
Integer i1=22;
Integer i2=22;
//i1==i2: ture
Integer i3=234;
Integer i4=234;
//i3==i4:false
3、两个封装类型进行equals()比较:
两个基本类型的封装类进行比较时,首先equals会比较类型是否相等,如果相等然后进行值比较。
4、封装类型使用equals()但参数是基本类型比较:
这时候会将基本类型进行装箱操作,转为封装类型然后进行值比较。
类型二:概念问题
概念问题考点就是8大基本类型的所占字节数。
类型三:有关拆箱和装箱问题
这类问题的关键主要是要注意看清楚是基本类型还是包装类型,如果是包装类型就要注意类型转换问题以及装箱拆箱的问题。
这里需要注意的是自动装箱和类型转换不能同时进行,这点主要体现于D选项。
double d=5.3e12;相当于5.3*10的12次方,符合要求
double d=3(int会自动转换类型);
Double D=3;错(自动装箱类型必须严格按照拆箱后的类型)
Double D=3.0;对
题二
首先a1和a2进行比较,因为值在-128到127范围内,所以==是true,A正确
d1为包装类,d2为基本类,包装类和基本类在进行==比较时,包装类会自动拆箱,那么也就是进行值比较,==结果为true,B正确
b1和b2进行比较,值不在-128到127范围内,也就是说相当于会创建两个对象,==为false
c1和c2比较,因为及时值一样,但是是两个new Integer,所以是两个对象==为false;
这里进一步对a1和a2以及b1和b2做解释,为什么创建方式相同但前者相等后者就不相等呢?
Integer a1=17:这种方式其实相执行的是Integer.valueOf(17),返回的是缓存的Integer对象,而这个缓存的范围也就是-128到127
所以a1和a2返回的是同一个对象,b1和b2不在缓存池范围内,返回的都是新建对象,所以前者==为true后者false。
题三
本题的关键就是要知道paeseInt()方法和intValue()方法的返回值。
IntValue():将Integer对象类型变成int基本类型;
parseInt():将String类型变成int基本类型;
valueOf():将String类型变成Integer对象类型;
所以a和b都为int的整型变量;
十一、this和super关键字的使用
this关键字:每个类中都会有一个隐藏的this指针,这个this指针的作用就是相当于当前这个类的一个引用,就相当于Study st=new Study() 中的这个st的作用一样。
super关键字:子类继承父类时,有一个super关键字,而这个关键字可以看做是父类的引用,比如可以通过super关键字调用父类的构造函数,当我们在子类的方法中使用:super():调用父类无参构造、super(变量):调用父类有参构造、super.变量:访问父类的成员变量等等
那么就可以知道this()是自己对象引用,那就相当于调用当前自己对象的构造函数,而super()是调用父类的构造函数,了解继承相关概念的可以知道,当子类调用构造函数创建实例时,会先调用父类的构造函数。所以super()一定在第一行。并且这两个不能再同一个构造函数中使用,所以B错误,C也错误
可以知道this()和super()的效果相当于创建对象,所以在静态static中是不可以使用的,因为静态中只能使用静态,所以在main方法中也不能出现这两个关键字(因为main方法也是static修饰)。D错误
十二、字节流与字符流相关
类型一
对于字节流与字符流相关的题,最常见的就是问那几个类属于字节流哪几个类属于字符流。
简单来说,以Stream为结尾的都是字节流,以Reader和Write为结尾的都是字符流。
类型二:
节点流:从一个节点(数据源等)读取数据;
处理流:对一个流进行封装;
十三、继承与多态相关总结(类的创建顺序)
类型一:
这类题目考察的主要就是对子类和父类的什么时候进行初始化。
子类引用父类的静态字段,只会导致子类的加载,父类的初始化,而子类并不会进行初始化。
所以父类初始化执行静态块,而子类不执行。打印结果为P.is init。
不会初始化子类的几种
1. 调用的是父类的static方法或者字段
2.调用的是父类的final方法或者字段
3. 通过数组来引用
类型二
这类题主要考察的就是子类和父类的加载顺序是怎样,一般情况下都会喜欢创建子类然后询问一些打印顺序。
加载顺序:
父类静态块-->子类静态块-->父类非静态块(包括属性)-->父类构造函数-->子类非静态块(包括属性)-->子类构造函数
本题new Sub()创建子类对象,sub对象继承Base对象,会先创建父类对象,父类对象中有无参构造Base(),然后调用执行callName()方法,但是注意!因为子类也重写了callName()方法,在父类方法的无参构造中的这个callName()实际调用的是子类的重写的方法,而不是父类的callName,但是此时才执行到父类构造函数,还没有执行加载子类属性(子类的baseName),所以会导致打印结果为null,而不是sub,更不是base。
题2
new Test(),Test继承与类A,在这里面,子类Test初始化之前会初始化父类A,也就是会执行C c=new C(),然后打印C,然后接下来会执行父类的构造函数,但是在子类的构造函数中,因为已经显式调用了父类有参构造super("B"),所以接下来执行父类的有参构造,打印B,然后剩下方法继续打印一个B,所以结果为CBB。
这里需要注意的就是子类和父类的一些初始化的顺序,如果子类的构造函数里面没有显式调用的话,那就会执行父类的无参构造,也就是会打印CAAB(执行父类成员打印C->执行父类无参构造打印2个A,子类无参构造打印B)
题3
概念问题,因为父类可以有自己的私有方法和变量,以及大家对私有的理解,可能有一部分同学就觉得父类无法访问子类的私有属性已经方法,那么反过来也是一样,但其实并不是。
子类继承父类的所有成员(包括一些私有),只不过是不能直接访问私有属性(但依旧是继承的),但要注意构造函数不属于成员,不被子类继承,只能通过调用。
题4
本题是对方法重写的相关知识考查
首先明确重写的要求:方法名,参数,返回值类型完全相同才属于方法重写。
A.正常的方法重写 正确
B.方法名和参数相同,但返回值类型不同,编译错误;
C参数类型不同,返回值不同,属于子类自己的方法;
D.和C选项同理。
题5
m1方法为父类私有,子类无法重写;
m2方法为default,如果是包外子类就无法访问;
m3方法为protected,子类一定可以继承和重写;
m4方法为静态方法,子类无法重写。
类型三(多态)
这题首先是父类Base,然后有一个method方法,子类Son继承Base类,并重写method方法,以及有一个自己的方法methodB。然后使用向上转型的方法Base base=new Son()使用父类引用类型创建了一个子类对象,这种也是最常见的一种多态,对于这种有一个口诀:编译看右边,运行看左边。也就是说编译的时候是按照左边的类型,但运行的时候是运行右边的实例对象的方法。
那么本题错误的地方就在base.methoB(),因为Base类中没有methoB()方法,会导致编译错误。
题2
同样也是经典的继承关系Derived继承Base类病重写methodOne和tow两个方法,然后创建子类对象Base b=new Drived();然后调用b.methodOne(),编译看右边,运行看左边,那么运行的是子类中的methodOne()方法,然后子类这个方法中使用super.methodOne()方法,那么此时来到了父类的one方法中,打印了一个A,然后调用methodTow()方法,注意!关键点来了,很多人可能以为这里调用的是父类自己的methodTow方法,因为方法前没有别的引用,但其实这里会调用子类的methodTwo()方法,因为只要是被子类重写的方法,如果不使用super,那么都是调用子类的方法。
所以在子类的tow方法中有super调用父类的two方法,打印B,回到子类打印D,最后打印C。
结果为ABDC
十四、锁机制相关
在锁中常用的synchronized,在使用时都知道需要绑定一个对象来使用,而大部分情况都是锁的一段代码块,比如:
synchronized(object){
//同步内容
}
但是synchronized也可以锁方法,那么锁方法的时候锁的是哪个对象呢?
锁非静态方法时:
当在非静态方法中使用synchronized时,锁的就是当前这个this对象,也就是这个类的对象
锁静态方法时:
当在静态方法中使用synchronized时,锁的就是当前这个类的class对象。
所以上题中 ab方法是同一个对象,cd是同一个对象。
十五、异常机制相关
异常类的题目就考察点就比较广泛,所以最好是全面理解。
首先从最上层说起Throwable是Error(错误)和Exception(异常)的父类。
Error在此不做过多赘述,一般是发生严重错误导致JVM关闭(虚拟机错误和线程死锁)。而异常可以分为编译时异常和运行时异常。
这里简单说明
编译时异常:顾名思义,编译时期就可以检查出的异常,也可叫做检查时异常,比如IOException,当我们使用一些文件类的API时,编译器会提示我们需要进行try..catch捕获代码块,这是因为编译器知道你使用了文件类的API,如果文件错误或者找不到等可能会出现异常,所以建议你捕获异常然后处理。
运行时异常:顾名思义,运行时期才发现的异常,也就是只有运行的时候才会发现异常,而这类异常java会帮助我们抛出,所以不需要写try..catch块,最常见的数组下标越界、空指针等等,比如当我们访问一个越界的数组下标时此时编译器并不会提示错误也不会提示使用try..catch块,而我们运行后就会报出异常。
所以本题B选项,非运行时异常,那就是编译时异常是需要try..catch块捕获,B正确。D选项运行时异常不是必须用try.catch块捕获,错误。
这题的关键就是要知道,当抛出一个异常后,只会打印捕捉的对应的异常,及时有多个catch语句,也只会输出其中某一个,而不会逐级输出。
本题主要是try-catch-finally块的用法
大家使用的时候一般情况下都会按照标准规范来使用,也就是用了try块一般都会用了catch块或者finally块。但是注意的是有try块后必须要接catch块或者finally块其中之一,只要有一个存在就可以,所以不能同时省略catch和finally块
十六、引用传递与值传递问题
这类问题主要考察的就是调用一个方法,然后传递参数对象,然后打印参数是否发生变化。
值传递:意思是只把变量的值作为形参传递,而传递的方法中无论进行了什么操作对原变量不会造成影响。在JAVA中为值传递的主要是基本数据类型加上一个String
引用传递:引用传递主要是发生在对象中,因为Java中对象的实例是存放在堆中,我们是通过虚拟机栈帧中的引用去操作对象,所以我们在调用方法时传递的都是这个方法的引用,注意传递的是一个新的引用副本,不是原方法的引用,所以在别的方法中进行了一些对值的修改操作等是会影响到原对象的结果。
本题中注意是int的封装类Integer,所以在主方法中调用doSomething,然后传递这个Integer对象,这里相当于传递了一个副本引用。然后这个副本引用等于指向了新对象,而不是变化原来的引用。所以这里var1=1,var2=var1,var1==var2为true
题二:
本题和上题一致,但这题唯一注意的点就是可能很多同学都知道String可以当做一个对象,因为String不属于八大基本类型,所以就误以为结果为test ok gbc,但注意String这个特例,因为String是不可变的(final修饰),所以其实可以当做一个值传递来看(为了方便记忆),本题可以和上题参考图一样。
String内存结构图:
十七、final和abstract关键字
final修饰变量:
当final修饰变量时表示该变量不可变,也就是我们常说的常量,但这里需要注意一点的是,当我们给一个对象使用final字段时,表示该对象引用不可以改变,但是这个对象的值是可以修改的,比如我们常见的StringBuffer和StringBuilder都是final修饰的,但是我们可以通过append进行字符串的添加操作,这里表示的是这个对象的引用不可以重新赋值,而不是对象的值不能修改。如果是基本数据类型就不需要考虑这个问题。
十八、序列化有关问题
序列化问题的关键就是在于可能很多人对这方面的知识不是很了解,因为平常学习可能会接触得比较少。
先简单说明一下序列化:
序列化就是将对象数据转换成一个字节流数据,便于在网络上进行传输。而在Java中是通过实现Serializable接口来标记告知JVM对该类进行序列化(仅仅只是一个标记作用)。
而Java在序列化时不会实例化static变量以及transient修饰的变量,transient的作用主要是声明序列化时忽略该字段。
所以本题中类有一个static修饰的i变量和一个正常的成员变量word,然后创建对象并对这两个属性赋值“123”和2,所以序列化后的数据word为123,i=0(默认值)而不是2。
十九、集合类相关
常见的就一些集合类属于哪个接口以及一些线程安全类问题等,与其他的相比较为简单一点。
这里大家可能都知道HashMap和一些HashTale的区别(经典八股了),但有些同学可能并没有去详细看过Map类,就比如HashMap是实现Map接口呢还是继承Map类呢?而HashTable的继承和实现又有什么区别呢?比如本题选项中的Dictionary类,大家可能也见得比较少,就好比D选项单独拎出来改成一个判断题来判断对错,很多同学可能就可能不太清楚了。
题二:数组
在Java中数组是被看做一个对象的,那么就是一个引用类型,所以肯定继承与Object方法,但是并没有重写equals方法,所以并不是比较数组中的元素,只有Arrays.equals()才是比较数组中的内容。
题三:线程安全问题
有关线程安全的类想必大家都非常熟悉,无论是List还是Map类的大家都了解,但是对于Stack可能就不太清楚(算法中用的比较多),所以这里注意Stack也是线程安全的
二十、反射相关
反射相关的考题一般是围绕反射相关的一些API,以及本身的知识也是属于比较重要且常见的一部分。
反射里面有些API是获取一些公有的,有的是获取所有的(包括私有)的方法,所以要注意区分。
无论是方法还是属性,一般的规律是带Declare的方法就是获取所有的,而不带的是获取公有的。
getDeclaredMethods()
:获取当前类中声明的所有方法,不包括继承自父类的方法。
getMethods()
:获取当前类及其父类中声明的所有公共方法。
二十一、Java中常用但是细节问题
Switch:
Switch也属于日常开发中能够经常见到的用法,但大部分情况大家都是根据int或者String来进行判断,而其他几种可能使用得比较少。
而Switch也支持char short byte int Enum等,而String类型是JDK8添加支持, 所以当问到浮点类型比如float,double要知道是不支持的就可以。
三目运算符:
这题如果不了解三目运算符的规则可能会是这样想:条件为true,执行new Integer(1)返回给o1,o2=new Integer(1),然后打印1,1;但其实结果为1.0和1,这是因为三目运算符进行了类型转换。本题中三目运算符结果有new Integer也有new Double,而三目运算符必须保证类型一致,所以会对类型进行自动提升,那么在编译后的结果其实是 Object o1=true?new Double(1):new Double(2.0); 所以o1返回的是1.0;
三目运算法类型转换问题:
三目运算符必须保证类型一致,如果不一致会对类型进行自动提升。
main方法:
main方法想必大家都不陌生,但可能有一部分没怎么考虑过main方法中的参数String [] args,因为没怎么用过所以不太了解。
其实main方法就可以看做java程序执行的入口,而且入口可以传入一个字符串数组。
所以java MyTest就是执行的java命令,而后面的a b c就是入口参数,也就是传入string数组的参数。
null:
这里关键的地方就在于这个null,可能一般没有这样子写过,所以不清楚到底可以不可以这样子写。
首先一点,静态的方法可以直接用类名来访问,但同时也可以用对象来访问
其次,null可以被强制转换成任意类型的对象,于是就可以用来执行静态方法了。
导包问题:
lang包是java语言的核心包,是Java程序必备的包,有解释器自动引入,无序手动导入。
二十二、JVM相关
JVM中常见参数:
- -Xms: 初始堆大小
- -Xmx: 最大堆大小
- -Xmn 年轻代大小
- -XX:SurivorRatio=3 也就是说Eden区与Surivior区的大小比值为3:1:1 默认值为8(8:1:1)
PS:本篇中出现的题目是在博主在这将近一千道中挑选出一部分较为经典的题目用作示例,因为本篇篇幅较长,也花了好几天的时间编写,难免会出现一些错误和纰漏,如有发现错误的地方,可以在评论区进行指正,本篇的一些相关知识都是笔试中喜欢的考点,但这部分又很少会在面试的八股中出现,所以对于一些只背了八股的同学,这些内容可能会比较生疏,最后也是希望本篇文章可以帮助到大家,无论是应付笔试面试还是日常的开发中,本篇都会有所帮助。