当前位置:   article > 正文

Java 基础面试300题 (141- 170 )

Java 基础面试300题 (141- 170 )

Java 基础面试300题 (141- 170 )

141. 编译运行以下代码时会发生什么?

class Mammal {}
class Cat extends Mammal { }
List<Mammal> list = new ArrayList<Cat>();
  • 1
  • 2
  • 3

上述代码将出现编译错误。这是因为为List指定了Mammal哺乳动物为其元素类型,而为ArrayList指定了Cat 为其元素类型 。在涉及到集合类型时,Java规则是,变量声明的类型必须与其实现的类型相匹配。因此,需要在ListArrayList中指定相同的数据类型

142.下面代码中的第1行会编译吗?

class Mammal {}
class Cat extends Mammal { }
List<? super Mammal> mList = new ArrayList<Cat>(); // line 1
  • 1
  • 2
  • 3

第1行将导致编译错误。这是因为Cat 的层次结构比其超类Mammal 要低。因此,只有当<Cat>替换为<Mammal><Object>时,上述代码才会编译通过。

143. 以面代码有什么问题吗?

List<?> mylist = new ArrayList<? extends Mammal>();
  • 1

上面代码创建了一个名为mylist 的列表, 并在列表的类型声明中使用了通配符 (),会导致编译错误,因为不能够在声明部分使用范型通配符。泛型的通配符仅允许在出现在方法参数或返回值中。

144.以面下代码片段有效吗?

public void getList(T t)
  • 1

上述代码使用范型参数声明了名为getList()的方法(范型方法)但却没有定义范型参数,因而是错误的。 下述两种方式均可解决此问题:

//方式一,定义范型类
public class MyClass<T> {
public void getList(T t){
}
}
//方式二,定义范型方法 
public class MyClass  {
public <T> void getList(T t){
}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

145. 什么是有界(Bounded)范型类型?

有界泛型类型有助于限制可用作泛型参数的类型。如下代码示例:

public class Shape {
}
public class Circle extends Shape{
}
public class ShapeDrawer<T extends Shape> {
public void drawShape(T shape) {
System.out.println(Drawing Shape..);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上述代码声明了一个名为Shape的超类,Circle类是Shape的子类。代码还声明了一个ShapeDrawer类, 这是一个范型类 ,它并没有直接定义范型类型T,而是指定T 必须扩展Shape类, 以对T的类型实施了进一步限定, 这意味着范型 T应该是Shape 的子类,如果用不是Shape子类的参数调用drawShape() 方法 ,将发生编译错误。

146. Java 集合 API中的四个主要接口是什么?

java.util.Collection接口是Java 集合 API中的顶级接口。 它仅仅简单表达了作为一个整体单元操作的一组值。 它有两个主要的子接口SetList。 两者都用于存储一组数据值; 但存储方式略有不同。

List 允许重复的元素,同一元素可以多次出现。 此外,List是有序的,列表中的元素按插入的顺序存储,并保持此顺序。

Set不允许元素重复,而且其中的元素是无序的,Set不会保留 元素插入顺序。

Map接口也是一个顶级接口,用于存储键值对。

147. 如何搜索数组中的特定元素?

作为集合框架的一部分,Java提供java.util.Arrays 类 , 该类有几种实用方法, 可用于搜索数组中的特定元素。其中一种方法是Arrays.binarySearch方法(二分搜索法), 它返回一个整数, 表示正在搜索的元素(如果存在)的在数组中的索引, 如果不存在,返回 -1。 以下代码演示了其使用方法:

String [] strArr = {“one”, “two”, “four”};
System.out.println(Search index of one is:+Arrays.binarySearch(strArr, “one”));

//输出
Search index of one is:0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

148.如果不允许元素重复,但不关心顺序, 应选择那种 集合类型?

如果想避免重复并且不关心顺序,则应使用HashSetHashSetSet接口的实现,它是未排序和无序的。TreeSetLinkedHashSet也是Set的实现。二者都不允许重复。但TreeSet保持排序顺序,而LinkedHashSet保持插入顺序。

149. 用代码解释如何删除队列头?

Queue接口有有一个名为poll()的方法,可用于删除队列的头部。以下代码演示了这一点:

Queue<Integer> lList = new LinkedList<Integer>();
lList.add(100);
lList.add(200);
System.out.println(Removed– “:lList.poll()); // Line 1
  • 1
  • 2
  • 3
  • 4

此代码创建一个队列,并向其添加两个整数值。然后,它调用poll()方法。 输出如下:

The Element removed is: 100
  • 1

因此,poll()方法总是删除队列的头部,即在队列中添加的第一个元素。

150.哪种集合的实现允许增加或缩小其大小,并可按索引方式访问其元素?

ArrayListList接口的实现。它允许增加或缩减其尺寸。它有增加/缩减方法,可以增加或减少列表的大小。它还提供了对其元素的索引访问。 如下代码简单演示了ArrayList

List<Integer> myList = new ArrayList<Integer>();
myList.add(2);
myList.add(4);
myList.add(6);
myList.remove(1);
Integer num = myList.get(0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

151.简单解释Queue接口。

队列接口是Java 集合 API的一部分,它扩展了java.util.Collection接口。除了正常的集合操作外,队列还提供了FIFO(先进先出)等队列数据结构的功能。队列接口有 下面几种操作队列的方法:

  • peek():允许检查队列顶部的元素
  • poll():删除队列顶部的元素
  • offer():在队列中插入一个元素

152.简单解释Comparator接口 。

Comparator是一个可用于排序的接口。自Java 8以来,它一直被指定为函数接口。它仅有单个名称为compare的抽象方法。该方法接受两个对象,并返回一个布尔值,表示比较结果。比较器接口也可用于对自定义对象进行排序,为此,相应的类需要实现比较器接口,并为其compare方法提供具体实现。如果是Java 8或更高版本, 还可以使用lambda表达式实现比较器。

153. 队列接口主要有些什么方法?

下表是队列主要有下面一些方法:

方法描述
offer(E e)将对象添加到队列中。如果失败 ,不会抛出异常。
peek()返回队列中最后添加的对象。
poll()检查并返回队列中头元素,如果存在,将其从队列中移除。
remove(Object o )从队列中移除对象。
add(E e)将对象添加到队列中。如果添加失败,则抛出异常。

154.是否可以混合使用普通集合和范型集合?

可以混合范型集合和非范型集合。如下代码片段示例:

public void insertDouble() {
List<Double> myDoubleList = new ArrayList<Double>();
myDoubleList.add(2.0); // Line 1
myDoubleList.add(4.0); // Line 2
insertSomethingElse(myDoubleList);
}
public void insertSomethingElse(List myDoubleList) {//Line 3
myDoubleList.add(Hello World); //Line 4
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上述代码中,第1行和第2行添加两个双精度Double数到列表中,该列表是一个类型为Double的范型列表。 在第3行的insertSomethingElse()方法声明中,没有为参数myDoubleList变量指定泛型类型。因此,任何类型的值都可以添加到此列表中。第4行将一个字符串添加到该列表中。

155. Collection接口上有哪些重要方法?

以下是Collection 接口上的一些重要方法:

方法描述
add向集合中添加对象。
remove从集合中移除对象。
contains检查集合中是否存在对象。
size返回集合的长度。
iterate在集合上进行迭代。

156.Java中可用的包装类是什么?

包装类是对应于Java基础类型的类,其主要作用是将基础类型转换为对象类型,反之亦然。使用Collections时,包装类特别有用。由于Collections不接受原始类型,应使用相应的包装类型进行包装。Java支持以下包装类:

基础类型包装类型
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

157. 以下代码的输出是什么?

public class BooleanDemo {
public static void main(String a[]){
//create Boolean using boolean primitive type
boolean boo1 = true;
Boolean booObj1 = new Boolean (boo1); //line 1
System.out.println(Wrapper class Boolean output:+booObj1);
Boolean booObj2 = new Boolean (false); //line 2
System.out.println(Wrapper class Boolean output:+booObj2);
System.out.println(booObj1.booleanValue());
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

第1行创建一个布尔包装器类型boolObj1,对应于bool类型变量。第2行使用String值创建一个布尔包装器boolObj2。Java自动将包装类型转换为基础类型。此外,在布尔包装类上有一个名为booleanValue()的方法,返回原始布尔值。因此,上述代码将打印以下输出:

Wrapper class Boolean output: true
Wrapper class Boolean output: false
true
  • 1
  • 2
  • 3

158. 如何将字符串“100.55”转换为双精度(Double)?如何将双精度数100.55 转换为字符串?

可以使用 Double.parseDouble()方法将字符串转换为Double,如下所示:

Double doubleValue = Double.parseDouble(100.55);
  • 1

可以使用Double.toString()方法将Double转换为字符串,如下所示:

String stringValue = Double.toString(100.55);
  • 1

159.以下代码的输出是什么?

Double doubleValue = Double.parseDouble(Java);
System.out.println(doubleValue);
  • 1
  • 2

上述代码编译没有问题,但是在执行时会抛出NumberFormatException,这是因为JVM无法将字符串Java转换为Double值。

160.什么是Java中的包装类?

Java是一种面向对象的语言。但是Java中的基础数据类型不是对象类型。有时,需要这些类型的对象等价物。比如使用Collections时, 由于集合只能包含对象,不能包含基础类型。为了解决这个问题,Java引入了包装类,用来将基础类型包装成对象。每个基础类型都有一个相应的包装类,可以创建该类型的对象。同样,也可以将包装对象转换为基础类型。例如,与int 基础类型对应的包装器类是 java.lang.Integer。Java在基础类型和相应的包装类之间自动转换。

161.什么是自动装箱?

自动装箱(和自动拆箱)是Java 5中引入的一项功能,它可以帮助程序员减少一些冗余代码。

例如,为了给包装类分配一个基础类型的值,如果没有自动装箱,则需要按以下方式编写包装代码:

Integer integerValue = new Integer(1000); //wrapping
  • 1

通过自动装箱,上述代码可以重写如下:

Integer integerValue = 1000;
  • 1

同样,为了将包装类型的值分配给基础类型 ,需要编写解包代码。如下示例:

Integer integerValue = 1000;
int iValue = integerValue.intValue(); //unwrapping
  • 1
  • 2

通过自动装箱,上述代码可以重写如下:

Integer integerValue = 1000;
int iValue = integerValue;
  • 1
  • 2

162. 如何在Java中创建线程?

在Java中创建线程有两种方法:

通过扩展Thread类:在这种方法中, 需要创建一个扩展内置Thread类的类,重写其run()方法。如下代码示例:

public class MyThread extends Thread {
public void run(){
System.out.println(In Thread Body..);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5

通过实现Runnable的接口:在这种方法中,需要创建一个实现内置Runnable接口的类, 实现该接口的run()方法。 如下代码所示 :

public class MyThread implements Runnable{
public void run(){
System.out.println(In Thread Body..);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5

163. Java中有哪几种不同类型的线程?

Java中有2种类型的线程: 用户定义的线程和守护线程。

用户定义的线程是由用户以编程方式创建的线程, 它们的优先级较高。JVM会等待这些线程执行完成。

守护线程主要由JVM创建(虽然用户定义的线程也可以显式设置为守护线程),通常用于后台进程,如垃圾收集。

一旦所有用户线程(非Daemon线程)停止运行,JVM就会停止运行,JVM并不会等待守护线程停止,或执行完成。

164.是否可以不调用线程对象的start()方法,直接调用其run() 方法?

可以直接调用线程对象的run()方法,而不调用其start()方法。但这没有什么意义,因为,它不会产生新的线程,run()方法中的代码将在调用它的同一线程中执行。

165.当执行以下代码时,幕后会发生什么?

class Test {
public static void main(String argument[]) {
System.out.println(Thread Example...);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5

执行上述代码时,JVM会首先创建一个线程, 该线程执行main方法中的代码。 执行完毕,线程终止。

166. Thread类主要有哪些方法?

方法描述
start()启动线程并调用 run() 方法。
run()定义线程中执行的代码。
sleep()使运行中的线程暂停指定的时间。
setName()将线程的名称设置为指定的值。
join()在不超过指定的多时间内,等待线程死亡。
isAlive()返回一个布尔值,指示当前线程是否存活。
setPriority()将线程的优先级更改为指定的值。

167.线程有哪些状态?它们之间是什么关系?

线程有下面五个状态。如下表所示:

状态描述
New (新建)创建了一个新的线程,但尚未调用 start() 方法时,线程处于新状态。
Runnable (可运行)在调用 start() 方法后,但线程调度程序尚未开始执行线程之前,线程处于可运行状态。
Running (正在运行)当线程调度程序开始执行线程时,线程处于运行状态,执行 run() 方法体内的代码。
Waiting / Blocking(等待/阻塞)如果线程是活动的,但不符合运行条件,则处于阻塞状态。
Dead (死亡)线程执行完毕后,进入死亡状态。

168. 如何使用Thread类创建线程 ?

以下代码使用“线程”类创建一个线程:

class MyThread extends Thread {
public static void main(String argument[]) {
MyThread thread = new MyThread ();
thread.start(); // Line 1
}
public void run() {
System.out.println(Inside Run Method..);// Line 2
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面的代码定义了一个名为MyThread的类,该类扩展了Thread类。执行第1行时,会生成一个新线程,然后该线程将执行run()方法中的代码。

169.如何使用 Runnable接口创建线程?

下面代码通过实现Runnable接口创建一个新线程:

class MyThread implements Runnable {
public static void main(String argument[]) {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread); //Line 1
thread.start(); // Line 2
}
public void run() {
System.out.println(Inside Run Method..);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上面的代码定义了一个名为MyThread的类,该类实现了Runnable接口 。然后, 创建了一个该类的对象 myThread,并在第1行将其传递给Thread类以创建一个新线程对象。 第2行调用start()方法生成一个新线程, 并执行run()方法中定义的代码。

170.是否可以创建多个线程? 多线程之间如何相互通信?

可以在Java程序中创建多个线程。对于两个线程相互通信,需要使用来自Object类的方法wait()notify()notifyAll()

wait()方法导致当前线程暂停,直到其他线程在同一对象上调用notify()

如果有许多对象都在等待特定对象,notify()方法会导致任何一个线程恢复(执行)。notifyAll()方法会使所有等待特定对象的线程恢复(执行)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/667617
推荐阅读
相关标签
  

闽ICP备14008679号