Nowcoder Java专项练习
1.String字符串
1.1String的不可变性
以下代码执行后输出结果为( )
答案:hello and dbc
解析:
String类型和数组都为引用数据类型。在main函数中调用fun方法传入的是str和ch的堆内存地址。
但是对于str,String类型被
final
修饰,不能够被继承,也就是值不能够被修改。String str = new String("hello");
这段代码创建了两个对象,一个是在堆空间创建了一个String类型的str变量,另一个是在堆空间的字符串常量池中添加“hello”字符串。在fun方法中,将“world”赋值给
形参str
,只是在堆内存中开辟了一个新的内存地址,str指向了新的内存地址,但是成员属性str指向堆内存的地址并没有改变,所以还是“hello”。而ch[0]指向的是堆内存中对应地址的对象的内容,所以值发生改变。
2.子父类问题
2.1子父类和权限修饰符
以下代码的输出的是()
答案:编译出错
解析:父类private的成员变量,根据权限修饰符的访问控制范围,只有在类内部才能被访问,就算是他的子类,也不能访问。
这里如果将Person p = new Child();改成Person p = new Person();代码依然无法通过编译,因为子类作用域中访问不到父类的私有变量,无法为其生成正确的字节码。另外,一个Java文件中不能有两个public类。
2.2子父类执行顺序
答案 :
LoadB
LoadA
CreateB
CreateA
子父类的执行顺序:
- 父类静态变量和静态初始化块,按在代码中出现的顺序依次执行。
- 子类静态变量和静态初始化块,按在代码中出现的顺序依次执行。
- 父类实例变量和实例初始化块,按在代码中出现的顺序依次执行。
- 执行父类构造方法。
- 子类实例变量和实例初始化块,按在代码中出现的顺序依次执行。
- 执行子类构造方法。
2.3两同两小一大原则
- 两同:子类的方法名和参数列表必须和父类完全一致
- 两小:子类的返回值与父类的相同,或者是父类返回值的子类;子类的声明的异常与父类的相同,或者是父类中声明异常的子类。
- 一大:子类的访问权限必须大于等于父类的访问权限。仅对于引用数据类型。(public > protect > 缺省 > private)
3.多重继承的概念体现方式
- 实现一个或多个接口
- 继承一个类并实现一个或多个接口
- 通过内部类去继承其他类
4.抽象类和接口的区别
- 对于定义方式:抽象类是一个类,可以包含有成员变量、成员方法和构造方法;而接口仅包含定义的常量和成员方法,没有方法体实现,也没有成员变量。
- 对于继承实现方式:一个类只能继承一个抽象类,而一个类可以同时实现多个接口。
- 对于抽象方法:抽象类可以定义抽象方法和非抽象方法,而接口仅能定义为抽象方法。
- 对于方法的实现:实现接口的类必须实现接口的所有方法,而继承抽象类的类必须实现所有的抽象方法(否则子类也必须声明为抽象方法),非抽象方法可以不实现。
5.权限修饰符
5.1外部类、内部类和局部内部类的权限修饰符
类 | 权限修饰符 |
---|---|
外部类 | public、缺省(default) |
内部类 | public、protected、缺省(default)、private |
局部内部类 | 没有权限修饰符,只能在当前方法或语句块中访问 |
6.构造函数调用or继承?
构造函数不能被继承,构造方法只能被显式或隐式的调用。
7.类型转化
7.1包装类类型转化
以下语句返回值为 true 的是()
答案:AB
对于A选项:a1、a2赋值给Integer类型,自动装箱。对于–128到127(默认是127)之间的值,Integer.valueOf(int i) 返回的是缓存的Integer对象(并不是新建对象),变量所指向的是同一个对象,所以a1==a2返回true
选项B:d1为包装类Integer,而d2为int类型,Integer和int比较,Integer类型的数据会自动拆箱,所以B正确。b1、b2、c1、c2都创建的新对象,内存地址不同,C、D错误。
8.Java 中final、finally和finalize的区别
final
是一个关键字,可以用来修饰类、方法或变量。
当一个类被声明为final时,表示该类不能被继承。当一个方法被声明为final时,表示该方法不能被子类重写。当一个变量被声明为final时,表示该变量是一个常量,不能再被修改。finally
是一个关键字,用于与 “try” 或 “catch” 一起使用,表示无论是否发生异常,都需要执行其中的代码块。finalize
是一个方法名,用于垃圾回收(GC)。在 Java 中,当对象不再被引用时,GC 会尝试清除该对象的内存,但在清除之前会调用该对象的 finalize() 方法进行资源回收。
9.==和equals()的区别
1. ==操作符==
操作符专门用来比较变量的值是否相同。
- 基本数据类型:比较的是他们的值是否相同。
- 引用数据类型:比较的是他们的内存地址是否同一地址。
引用类型对象变量其实是一个引用,它们的值是指向对象所在的内存地址,而不是对象本身。
2. equals方法equals
方法常用来比较对象的内容是否相同。
Java当中所有的类都是继承于Object这个超类的,在Object类中定义的equals方法:
- 未重写equals方法的类:Object中的equals方法实际使用的也是==操作符,比较的是他们的内存地址是否同一地址。
- 重写了equals方法的类:实现该类自己的equals方法比较逻辑(一般是比较对象的内容是否相同)。比如:
- String:比较字符串内容,内容相同则相同;
- Integer:比较对应的基本数据类型int的值是否相同(==操作符)。
10.Map接口和Entry接口的关系
Map接口和Entry接口是Java编程语言中的两个接口,两者之间存在一定的关系。
==具体来说,Map.Entry接口是Map接口的一个内部接口,它表示Map对象中的一个键值对(即一条记录)。 Map接口提供了访问Map对象中各个记录的方法,而Map.Entry接口则提供了访问记录中键和值的方法。==
因此,当我们需要对Map对象中的各个记录进行遍历或操作时,通常需要使用Map.Entry接口和Map接口配合使用。 例如:
在这个示例中,我们先创建了一个Map对象,并添加了几条记录。 然后使用entrySet()方法获取Map对象中所有的记录,遍历每个记录(即每个Map.Entry对象),并使用getKey()和getValue()方法获取每个记录的键和值。 我们可以根据这些键值对执行任何想要的操作。
11.通配符和泛型的区别
通配符和泛型都是Java中用来处理不确定类型的关键字,但它们之间有以下区别:
- 使用位置:泛型通常用来指定类、方法或接口的参数类型,而通配符则通常用在作为函数参数的类型上。
- 粒度:泛型是“更粗”的类型,它可以指定具体的数据类型,如List
,而通配符是“更细”的类型,它表示某些不确定类型的集合,如List<?>。 - 操作范围:使用泛型的代码可以对特定类型的对象进行操作,而使用通配符的代码则只能进行局部的一些操作,例如遍历集合。
- 单一性:通配符是一种单一的类型,可以表示任意类型的集合,而泛型可以指定一个或多个具体的类型参数。
- 语法:泛型使用<>表示类型参数,而通配符使用?表示未知的类型。通配符可以使用extends关键字限制类型范围,例如List<? extends Number>表示仅能包含Number及其子类类型的集合。
总体而言,泛型和通配符都是Java中非常重要的类型处理机制。泛型要更灵活一些,它能够具体地指定类型,通常用于类、方法或接口声明。而通配符则是更简单的处理机制,它用于对多个不同类型的对象进行操作。