java面试题(部分)(持续更新)
Posted q1427094386
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java面试题(部分)(持续更新)相关的知识,希望对你有一定的参考价值。
java面试题
一、String
- concat(String );
如果参数字符串的长度为 0,则返回此 String 对象。 否则,创建一个新的 String对象,用来表示由此 String
对象表示的字符序列和参数字符串表示的字符序列连接而成的字符序列
- toLowerCase();
使用默认语言环境的规则将此 String 中的所有字符都转换为小写,并返回一个新的字符串(这一点很重要)
- replace(char oldchar,char newchar);
String中的replace(char oldchar,char
newchar)方法意思将这个字符串中的所有的oldchar全部换成newchar,并返回一个新的字符串(这一点很重要)
注意:StringBuilder修改原对象。
- String.trim()方法
去除字符串两端,不仅仅是空格字符,它总共能去除25种字符: (’/t’, ‘/n’, ‘/v’, ‘/f’, ‘/r’, ’ ',
‘/x0085’, ‘/x00a0’, ’ ', ’ ', ’ ', ’ ', ’ ', ’ ', ’ ', ’ ', ’ ', ’ ',
’ ', ’ ', ‘?’, ‘/u2028’, ‘/u2029’, ’ ', ‘?’) 并返回一个新的字符串(这一点很重要)。
以上方法如果源字符串为空,抛异常(NullPointerException)。
- The java.lang.StringBuilder.insert(int offset, char c) method inserts the string representation of the char argument into this sequence.
- java.lang.StringBuilder.delete()
public StringBuilder delete(int start, int end) -
start -- 这是开始索引(包含)。
-
end -- 这是结束索引(不包含)。
二、字符串比较
- String、new String()区别
String str1 =
“abcd"的实现过程:首先栈区创建str引用,然后在String池(独立于栈和堆而存在,存储不可变量)中寻找其指向的内容为"abcd"的对象,如果String池中没有,则创建一个,然后str指向String池中的对象,如果有,则直接将str1指向"abcd”";
如果后来又定义了字符串变量 str2 = “abcd”,则直接将str2引用指向String池中已经存在的“abcd”,不再重新创建对象;
当str1进行了赋值(str1=“abc”),则str1将不再指向"abcd",而是重新指String池中的"abc",此时如果定义String
str3 = “abc”,进行str1 == str3操作,返回值为true,因为他们的值一样,地址一样。
但是如果内容为"abc"的str1进行了字符串的+连接str1 =
str1+“d”;此时str1指向的是在堆中新建的内容为"abcd"的对象,即此时进行str1==
str2,返回值false,因为地址不一样。
String str3 = new String(“abcd”)的实现过程:直接在堆中创建对象。如果后来又有String str4 =
new
String(“abcd”),str4不会指向之前的对象,而是重新创建一个对象并指向它,所以如果此时进行str3==str4返回值是false,因为两个对象的地址不一样,如果是str3.equals(str4),返回true,因为内容相同。
String str1 = "abcd";
String str2 = "abcd";
String str3 = new String("abcd");
String str4 = new String("abcd");
System.out.println(str1`==`str2);//true地址一样
System.out.println(str3`==`str4);//false,但地址不一样
System.out.println(str3.equals(str3));//true,值一样
System.out.println(str2.equals(str3));//true,值一样
System.out.println((str1+"a")==(str2+"a"));//false;进行了+连接地址不一样
参考网址:深入理解Java中的String
三、接口常量定义
-
public:使接口的实现类可以使用这个常量。
-
static:static修饰就表示它属于类的,随的类的加载而存在的,如果是非static的话,就表示属于对象的,只有建立对象时才有它,而接口是不能建立对象的,所以接口的常量必须定义为static。
-
final:final修饰就是保证接口定义的常量不能被实现类去修改,如果没有final的话,由子类随意去修改的话,接口建立这个常量就没有意义了。
四、构造函数
- This(): The constructor test004() is undefined。
默认空构造器需显式进行定义,定义了一个带参的构造器覆盖了默认的,而此时你再使用默认的构造器就会导致异常。
- 构造函数调用构造函数
不能在程序中像调用其他方法一样去调用构造方法(必须通过关键词new自动调用它)。但我们可以在一个构造方法里调用其他重载的构造方法,不是用构造方法名,而是用this(参数列表)的形式,根据其中的参数列表,选择相应的构造方法。
构造方法中调用构造方法,遵循以下原则:
1、使用this调用另一个重载构造器,只能在构造器中使用;
2、必须写在构造器执行体的第一行语句;
在Java中,如果一个构造方法想调用另一个构造方法,需要是用this(参数列表)的形式,自动调用对应的构造方法。不可以直接使用类名进行调用。
- super()、this()
super()和this()都必须在构造方法的第一行。
super()和this ()不能共存,否则编译时会报异常。
子类的构造方法上如果没有明确的调用父类的构造方法,它会默认地调用父类的不带参数的方法;
如果你继承的父类没有无参数构造函数,那么你这个类第一句必须显示的调用super关键字来调用父类对应的有参数构造函数,否则不能通过编译。
- 构造函数调用构造函数
构造方法前面是没有任何返回符,不能加任何返回类型,包括void.一个构造方法一旦加了void,那么这个就不是构造方法了,变成了一个普通的方法。
- 构造函数也遵循普通函数的访问机制
public:所有的类都可以使用;
protected: 本包以及子类可以使用;
default:本包可以使用;
private:仅本类可以使用
五、继承
- 子类可以不用申明,可以自动具有父类可访问的方法;
class Mid {
public int findMid(int n1, int n2) {
return (n1 + n2) / 2;
}
}
public class test005 extends Mid {
public static void main(String[] args) {
int n1 = 22, n2 = 2;
// insert code here
test005 m1 = new test005();
int n3 = m1.findMid(n1, n2);
System.out.print(n3);
}
}
- 父类子类强转类型时注意:
class Y extends X
X xRef = new Y();
Y yRef = (Y) xRef; //不报错
Y yRef = xRef;//报错 type mismatch: cannot convert from X to Y
【77】X xRef = new X();
(Y)xRef.xxxx
//Exception in thread “main” java.lang.ClassCastException: Star cannot be cast to Sun
at test077.main(test077.java:19)
调用方法时,皆以实际类的方法输出为准
强制类型转换:要把父类型转换为子类型,需要强制。
- 子类重写继承的方法时,不可以降低方法的访问权限
子类继承父类的访问修饰符要比父类的更大,也就是更加开放,假如我父类是protected修饰的,其子类只能是protected或者public,绝对不能是friendly(默认的访问范围)或者private,当然使用private就不是继承了。
访问修饰符范围
关键字 | 同一个类中 | 同一个包中 | 派生类中 | 其他包中 |
---|---|---|---|---|
private: | √ | |||
默认 | √ | √ | ||
protected: | √ | √ | √ | |
public: | √ | √ | √ | √ |
注意:不写默认位friendly
父类引用可以指向子类对象,子类引用不能指向父类对象、泛型。
Java中只要调用子类的构造函数就一定会调用父类的构造函数,这是毋庸置疑的!有时我们并没有在父类中写有参和无参的构造方法,但是这样我们在定义子类对象时调用子类构造函数时,其实也调用父类的构造函数,这是系统自动为我们添加的“public Pen(){}”。但是如果我们在父类中已经自己定义了有参的构造方法,却没有定义无参的构造方法,那么此时系统是不会为我们自动添加无参的构造方法的,此时程序结果就会提醒你父类没有无参的构造方法,程序就会报错。
某类的protected 方法和属性在包外是不能通过该类对象进行访问的(你能在包外访问一个类的默认权限的方法和属性吗?当然不能),这就是为什么在某对象所在的包的以外的任何地方,你不可以通过该类的对象引用来调用它的protected 方法和属性,哪怕是在该类的子类中也不可以这样做。在该类包外的子类中能“看到“的只是子类自己继承来的protected 方法和属性,它是不能“看到“它的父类对象的protected方法和属性的。
也就是说你可以new 子类然后子类对象.protected属性…但是这样实际上访问的是子类继承来的属性…并不是父类的属性。
例: public class Test extends Acc {
public static void main() {
Acc obj = new Test();
System.out.println(obj.s + obj.r);
}
}
obj.r//r为父类protected,编译报错
Acc obj = new Test();=>Test obj = new Test(); //编译通过
总结如下:
- 子类可以通过继承获得不同包父类的protected权限成员变量和成员方法,在子类中可以直接访问;
- 在子类中可以通过子类的对象访问父类的protected成员变量和方法;
- 在子类中反而不能通过父类的对象访问父类的protected成员变量和方法;
- 在子类中不能通过其他子类的对象访问父类的protected成员变量和方法;
- 在与子类同包的其他类中不能通过子类的对象访问父类的protected成员变量和方法。
六、多态
使用父类类型的引用指向子类的对象;
该引用只能调用父类中定义的方法和变量;
如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用);
变量不能被重写(覆盖),“重写”的概念只针对方法,如果在子类中“重写”了父类中的变量,那么在编译时会报错。
七、接口
在Java8的新特性中有一个新特性为接口默认方法,该新特性允许我们在接口中添加一个非抽象的方法实现,而这样做的方法只需要使用关键字default修饰该默认实现方法即可。该特性又叫扩展方法。
因为接口定义的方法默认是public的,意思就是你没有任何访问修饰符的情况下,系统给接口的方法加上了一个public的访问修饰符。
而且修饰符只允许public(only public & abstract are permitted)。
八、时间方法
- LocalDate
// 取当前日期:
LocalDate today = LocalDate.now(); // -> 2014-12-24
// 根据年月日取日期:
LocalDate crischristmas = LocalDate.of(2014, 12, 25); // -> 2014-12-25
// 根据字符串取:
LocalDate endOfFeb = LocalDate.parse("2014-02-28"); // 严格按照ISO yyyy-MM-dd验证,02写成2都不行,当然也有一个重载方法允许自己定义格式
LocalDate.parse("2014-02-29"); // 无效日期无法通过:DateTimeParseException: Invalid date
LocalDate date3 = LocalDate.parse("2014-06-20", DateTimeFormatter.ISO_DATE);
(An exception is thrown at runtime) DateTimeFormatter.ISO_DATE_TIME
- LocalTime
LocalTime now = LocalTime.now(); // 23:11:08.006
LocalTime zero = LocalTime.of(0, 0, 0); // 00:00:00
LocalTime mid = LocalTime.parse("12:00:00"); // 12:00:00
九、断言
Predicate:
通常格式如:
(p -> oldData.getPrice() != null&&
十、Removelf(java8新增)
该方法将会批量删除符合filter条件的元素。该方法需要一个Predicate(谓词)对象作为参数,Predicate也是函数式接口,因此可以使用Lambda表达式。
xxx.removeIf(ele->((String)ele).length()<10);
xxx.removelf(e->e%2 != 0);
十一、ArrayList
- contains(obj)
contains方法调用的是indexOf方法
- indexOf(obj)
需要equals方法的支持。在未覆写equals方法的情况下默认调用的是Object类的equals方法,判断的是内存地址:this == obj。所以在需要的情况下应该覆写equals方法。
- List int是基本数据类型,只能用Integer
List //错误
List //正确
- remove(obj)
public E remove(int index)
移除此列表中指定位置上的元素。向左移动所有后续元素(将其索引减 1)。
public boolean remove(Object o)
移除此列表中首次出现的指定元素(如果存在)。如果列表不包含此元素,则列表不做改动。更确切地讲,移除满足 (o==null ? get(i)==null : o.equals(get(i))) 的最低索引的元素(如果存在此类元素)。如果列表中包含指定的元素,则返回 true(或者等同于这种情况:如果列表由于调用而发生更改,则返回 true)。
十二、异常
将派生于Error或者RuntimeException的异常称为unchecked异常,所有其他的异常成为checked异常。
1.调用一个checked异常的方法,例如IOException,至于原因我们前面已经讨论过了,如果抛出所有的checked异常时无法通过编译的。
2.程序运行过程中发现错误,利用throw语句抛出一个异常。
3.对于unchecked异常,无非主要是两种情况要么是可以避免的(Runtime Exception),要么是不可控制的。这些也是需要声明异常的。
常见异常场景
运行时的异常、error如果未捕获,如下报错:
Exception in thread "main" java.lang.Error: Error
at test021.doList(test021.java:14)
at test021.main(test021.java:5)
若捕获如下:
Caught java.lang.RuntimeException: Exception
方法引用抛异常方法,可以使用以下两种方式
Throws 异常(再次抛出异常)
Try{}catch 异常 (捕获异常) 注意:
catch(Exception e){}
catch(IOException e1){}
无法编译,Unreachable catch block for IOException. It is already handled by the catch block for Exception。
如果某方法抛出运行时异常(RuntimeException),该异常可以不捕获。
类别 | 常用异常类 |
---|---|
Error | AssertionError、OutOfMemoryError、StackOverflowError |
UncheckedException | AlreadyBoundException、ClassCastException、ConcurrentModificationException、IllegalArgumentException、IllegalStateException、IndexOutOfBoundsException、JSONException、NullPointerException、SecurityException、UnsupportedOperationException NumberFormatException |
CheckedException | ClassNotFoundException、CloneNotSupportedException、FileAlreadyExistsException、FileNotFoundException、InterruptedException、IOException、SQLException、TimeoutException、UnknownHostException |
java.lang.NegativeArraySizeException属于java.lang.RuntimeException
十三、转换
- 自动转换:
当一个较"小"数据与一个较"大"的数据一起运算时,系统将自动将"小"数据转换成"大"数据,再进行运算。
- 强制转换:
将"大"数据转换为"小"数据时,你可以使用强制类型转换。
int i = 0;
float f = 0;
i = (int)f; //不报错
i = f; //报错
- long转换String:
long a1 = 12;
String s1 = a1 + “”; // 法1:直接加空串
String s2 = String.valueOf(a1); // 法2:String.valueOf()
String s3 = Long.toString(a1); // 法3:Long.toString()
String s4 = (String)(long1*long2); //编译报错
- int转换String(Double, Float, Long 转成字串的方法大同小异):
String s = i + “”;
String s = String.valueOf(i);
String s = Integer.toString(i);
- float说明:
如果不声明,默认小数为double类型,所以如果要用float的话,必须进行强转 例如:float a=1.3; 会编译报错,正确的写法 float a = (float)1.3;或者float a = 1.3f。(f或F都可以不区分大小写)
十四、初始化
全局变量会自动初始化,全局变量的byte,char,short,int,long,float,double的初始化值都是0;布尔性的基本类型变量的默认值为 false,引用类型的变量是默认值为 null。
char 为0,显示为 。
如果局部变量没有初始化,定义处不会报错,引用时会编译出错。
成员变量都有默认初始化值。各种类型的默认初始化值如下:
1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。
2、单精度浮点型(float)的基本类型变量的默认值为0.0f。
3、双精度浮点型(double)的基本类型变量的默认值为0.0d。
4、字符型(char)的基本类型变量的默认为 “/u0000”。
5、布尔性的基本类型变量的默认值为 false。
6、引用类型的变量是默认值为 null。
7、数组引用类型的变量的默认值为 null。
局部变量里,必须初始化。
十五、集合
JAVA集合只能存放引用类型的数据,不能存放基本数据类型。
十六、方法调用
“在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。
基本类型的变体引用类型和String都不能直接当纯引用类型来用,比如Integer,Double等都是int与double的引用类型,但是你不能像普通引用类型那样直接对他的值做改变,因为在他们里面封装的原始int与double都用了final进行声明。所以你就算重新赋值了原始的int与double都不会改变。
十七、重写、重载
重写:(两同、两小、一大)
重写规则之一:重写方法不能比被重写方法限制有更严格的访问级别。
重写规则之二: 参数列表必须与被重写方法的相同。
重写规则之三:返回类型必须与被重写方法的返回类型相同。
重写规则之四:重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。
重写规则之五: 不能重写被标识为final的方法。
重写规则之六:如果一个方法不能被继承,则不能重写它。如private方法
重写规则之七:子类不能用 静态方法 重写 父类的非静态方法
重写规则之八:子类不能用 非静态方法 重写 父类的静态方法
重载:
- 参数类型、个数、顺序至少有一个不相同。
- 方法名一样,但参数类型和个数一样,返回值类型可以相同也可以不同,无法以返回类型作为重载函数的区分标准;
- 方法重载就是在类中创建多个方法,方法名相同,参数列表不同,调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法,体现多态性;
- 方法重载是让类以统一的方法处理不同类型数据(同方法名,不同参数列表)的一种手段;
- 重载overload,编译时,同一个类中,同名方法有不同参数列表(个数、类型),是一个类中多态性的表现,是静态分派,在编译期,通过静态类型而不是实际类型作为判定依据(静态方法也可以重载);
Final说明:
- 用final修饰的类不能被继承,即不能拥有自己的子类;
- final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。
注:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。- final修饰的变量表示此变量是“最后的、最终的”含义。一旦定义了final变量并在首次为其显示初始化后,final修饰的变量值不可被改变。
注: final修饰的变量,无论是类属性、对象属性、形参还是局部变量,这些变量都是需要进行显示初始化(即为其显示指定初始值)。
十八、反射
- getClass().getName()是在程序运行时获得运行时实例的类类型。
- .class.getName()是在编译阶段就确定了的,与运行时的状态无关。
十九、变量、属性、域(field)
变量和属性是有区别的:
变量是方法体中定义的,我们称为临时变量。
属性是类体中定义的。
- 而权限标示符只用于修饰属性和方法。不修饰变量。
- 方法中定义的临时变量在方法调用完成之后就不存在了,不需要用修饰符定义!
域即类成员(字段),通常是在类中定义的类成员变量。
二十、Main
此方法为java程序的入口方法,jvm在运行程序时,会首先查找main()方法。
其中public是权限修饰符,表明任何类或对象都可以访问这个方法,
static表明是静态方法,及方法中的代码是存储在静态存储区的,只要类被加载后,就可以使用该方法,不需要通过实例化来访问,可直接通过类名.main()直接访问,
jvm在启动时就是按照上诉方法的签名(必须有public和static修饰,返回值为void,且方法参数为字符串数组)来查找方法的入口地址,若找到就执行,找不到就会报错。
void表明方法没有返回值,
main是jvm识别的特殊方法名,是程序的入口方法。
字符串数组参数args为开发人员在命令行状态下与程序交互提供了一种手段。
注意:
- public与static没有先后顺序关系
static public void main(String[] args) - 也可以把main()方法定义为final
public static final void main(String[] args) - 也可以用syncchronized来修饰main()方法
static public synchronized void main(String[] args)
不管是哪种定义形式,都必须保证返回值为void,并有static和public关键字修饰,因为是入口函数,所以绝对不能用abstract关键字来修饰。
- 在main函数中使用了this后,会提示出错。
原因是在main函数中不能使用this,main函数属于static,main中必须生成一个确定的对象来调用方法,凡是属于static的,this均不能用。
二十一、switch
switch(A),括号中A的取值可以是byte、short、int、char、String,还有枚举类型。
二十二、while
while(注意,一定要boolean类型)
二十三、计算顺序
System.out.println(28 + 5 <= 4 + 29);
System.out.println((28 + 5) <= (4 + 29));
结果:
true
true
//只要出现全运算符号,+不实现字符串拼接。如28 + 5 / 4 + 29 。
以上是关于java面试题(部分)(持续更新)的主要内容,如果未能解决你的问题,请参考以下文章