《Java黑皮书基础篇第10版》 第11章【习题】

这篇文章详细讨论了Java中的继承概念,包括子类和父类的关系、单一继承与多重继承的区别,以及如何使用`super`关键字调用父类构造方法。同时,还涵盖了多态的定义、动态绑定和方法重写。此外,文章还介绍了ArrayList的使用,如添加、删除元素,以及如何创建和使用自定义的类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java语言程序设计 习题第十一章

11.2章节习题

11.1 下面说法是真是假? 一个子类是父类的子集

不是,子类可以拥有父类的数据域和方法,还可以拥有自己独有的数据域和方法

11.2 使用什么关键字来定义一个子类?

extends

11.3 什么是单一继承?什么是多重继承? Java支持多重继承吗?

单一继承是一个子类只能有一个父类

多重继承是一个子类可以有多个父类

Java不支持多重继承。在Java中,一个子类只能有一个父类,但是一个父类可以有多个子类

11.3章节习题

11.4 下面a中类C的运行结果输出什么? 编译b中的程序的时候将出现什么问題?

class A {
    
  public A() {
   
		System.out.println("A's no-arg constructor is invoked");
	} 
}

class B extends A {
    
	//B类虽然没有构造方法,但是编译器会自动创建一个无参构造方法
	//public B() {
   
	//同时,由于B没有明确的调用父类A的构造方法,super()也会被默认的构建出来,去调用A的无参构造方法
	//super();
	//}
}

public class Test {
   
	public static void main(String[] args) {
   
		//调用B类的无参构造方法来创建实例
		B b = new B(); 
  }
}

输出结果:

A's no-arg constructor is invoked
class A {
   
	public A(int x) {
    
  }
}

class B extends A {
    
	//编译器默认加了super(),想要去调用A类的无参构造方法,但是A类没有无参构造方法,所以报错
	public B() {
   
	}
}

public class C {
   
	public static void main(String[] args) {
   
		B b = new B(); 
  }
}

11.5 子类如何调用它的父类的构造方法?

使用关键字super

11.6 下面的说法是真是假: 当从子类调用构造方法时,它的父类的无参构造方法总是会被调用?

假,如果子类明确的调用了父类的有参构造方法,那么父类的无参构造方法就不会再被调用

11.4章节习题

11.7 下面说法是真是假:可以重写父类中定义的私有方法?

假,子类重写父类中的私有方法实际上是新定义了一个方法,和父类方法没有关系

11.8 下面说法是真是假:可以重写父类中定义的静态方法?

假,只能重写有访问权限的非private方法

11.9 如何从子类中显式的调用父类的构造方法?

使用super()

11.10 如何从子类中调用一个被重写的父类的方法?

使用super.method()

11.5章节习题

11.11 指出下面代码的错误:

public class Test {
   
	private double radius;

	//需要一个无参构造方法供B类中的构造方法来调用
	//public Test() {
   
	//}
	
	public Test(double radius) {
    
		//需要使用关键字this来指向数据域,不然就是局部变量了
		radius = radius;
	}

	public double getRadius() {
    
		return radius;
	}

	public double getArea() {
   
		return radius * radius * Math.PI;
		}
	}

class B extends Test {
   
	private double length;

	B(double radius, double length) {
   
		//父类的字段是private,不可以直接访问,需要使用super关键字来调用父类的构造方法来访问字段
		Test(radius); 
		//需要使用关键字this来指向数据域,不然就是局部变量了
		length = length;
	}

	@Override
	public double getArea() {
    
		return getArea() * length;
	}
}

11.12 解释方法重载和方法重写的不同之处。

对于方法重写,首先必须保证方法签名和返回值都相同,只有方法体是不同的,其次需要保证必须是子类重写了父类的方法,在Java中提供了@Override来检测是否重写了父类。

对于方法重载,首先只要返回值(大多数情况)和方法名相同即可,方法参数和方法体都可以不同;其次可以重载同一个类或父类的方法。

11.13 如果子类中的方法具有和它父类中的方法完全相同的方法签名,且返回值类型也相同,那么这是方法重写还是方法重载呢?

Override

11.14 如果子类中的一个方法具有和它父类中的方法完全相同的方法签名,但返回值类型不相同,这会存在问题吗?

11.15 如果子类中的一个方法具有和它父类中的方法相同的名字,但参数类型不同,那么这是方法重写还是方法重载呢?

Overload

11.16 使用@Override标注的好处是什么?

在Java中提供了@Override来检测是否重写了父类。

11.8章节习题

11.17 什么是多态? 什么是动态绑定?

多态意味着子类可以安全地进行向上转型,即子类型的实例对象可以指向父类型的引用变量;

动态绑定意味着实例对象调用实例方法时,是基于运行时实际的实例对象类型来调用的,并不是基于引用变量的声明类型

11.18 描述方法匹配和方法绑定之间的不同。

方法匹配:只要方法名,参数类型、数量、顺序一致,就可以根据引用变量的类型去匹配方法

方法绑定:运行时期才能决定实例对象的类型并用这个类型的实例去匹配方法

11.19 可以将以下实例赋值给Object[]类型的变置吗,new int[50]、new Integer[50]、new String[50] 或者 new Object[50]?

New int[50]不行,其他都可以

11.20 下面代码中哪里有错误?

public class Test {
   
	public static void main(String[] args) {
   
		Integer[] list1 = {
   12, 24, 55, 1};
		Double[] list2 = {
   12.4, 24.0, 55.2, 1.0}; 
		int[] list3 = {
   1, 2, 3};
		printArray(list1);
		printArray(list2);
		//在调用printArray()方法时,传入了一个int数组,但是该方法只接受一个Object数组作为参数,因此会导致编译错误。在Java中,int是一个基本类型,不属于某一个类或包,不是一个对象,而Integer是一个对象。在Java中,基本类型和对象类型之间不能自动转换。
		printArray(list3);
  }

	public static void printArray(Object[] list) {
    
    for (Object o: list)
			System.out.print(o + " ");
		System.out.println(); 
  }
}

11.21 给出下面代码的输出。

public class Test {
   
	public static void main(String[] args) {
   
			new Person().printPerson();
			new Student().printPerson(); 
	}
}

class Student extends Person {
    
	@Override
	public String getInfo() {
   
		return "Student"; 
		}
}

class Person {
   
	public String getInfo() {
   
		return "Person"; 
		}

	public void printPerson() {
    
		System.out.println(getInfo());
	} 
}

输出结果:

Person
Student
public class Test {
   
	public static void main(String[] args) {
   
		new Person().printPerson();
		new Student().printPerson(); 
	}
}

class Student extends Person {
   
  //private字段不可以访问,所以不可以Override
	private String getInfo() {
   
		return "Student"; 
	}
}

class Person {
   
	private String getInfo() {
   
		return "Person"; 
		}

	public void printPerson() {
    
		System.out.println(getInfo());
	} 
}

输出结果:

Person
Person

11.22 给出下面程序的输出。

public class Test {
   
	public static void main(String[]args) {
   
		A a = new A(3); 
  }
}

class A extends B {
   
  public A(int t) {
   
		System.out.println("A's constructor is invoked");
  }
}

class B {
   
	public B() {
   
		System.out.println("B's constructor is invoked"); 
  }
}

输出结果:

B's constructor is invoked
A's constructor is invoked

11.23 给出下面程序的输出:

public class Test {
   
	public static void main(String[] args) {
   
		new A();
		new B();
  }
}

class A {
    
	int i = 7;
	//对于new A(),首先会来匹配执行以下代码,并且A直接继承自Object,构造方法继承链终止。setI是方法重写,根据多态,会根据实例对象的实际类型匹配方法,所以会执行A类的setI方法
	//(2/2)构造方法继承链至此,执行setI,setI是方法重写,根据多态,会根据实例对象的实际类型匹配方法,所以会执行B类的setI方法
    public A() {
   
		setI(20);
		System.out.println("i from A is " + i);
}
  
	public void setI(int i) {
    
    this.i = 2 * i;
	} 
}

class B extends A {
    
	//(1/2)对于new B(),首先会来匹配执行以下代码,并且B直接继承自A,构造方法继承链向上继续
	public B() {
   
		System.out.println("i from B is " + i); 
  }

	public void setI(int i) {
    
		this.i = 3 * i;
	} 
}

输出结果:

i from A is 40
i from A is 60
i from B is 60
11.9章节习题

11.24 下面的说法是对还是错?

• 总可以成功地将子类的实例转换为父类。

对,即为向上转型

• 总可以成功地将父类的实例转换为子类。

错,不一定成功,可以利用instanceof判断

11.25 对于程序清单11-1和程序清单11-2中的GeometricObject类和Circle类,回答下面的问题:

a. 假设circle和object如下创建:

Circle circle = new Circle(1);
GeometricObject object = new GeometricObject();

下面的布尔表达式的值是 true 还是 false ?

//true
(circle instanceof GeometricObject) 
//true
(object instanceof GeometricObject) 
//true
(circle instanceof Circle)
//false
(object instanceof Circle)

b. 下面的语句能够成功编译吗?

Circle circle = new Circle(5) ;
GeometricObject object = circle; 

可以,这是向上转型

c. 下面的语句能够成功编译吗?

GeometricObject object = new GeometricObject(); 
Circle circle = (Circle)object;

不可以

11.26 假设 Fruit、Apple、Orange、GoldenDelicious 和 Macintosh 如下面的继承层次定义:

在这里插入图片描述

假设给出以下代码 :
Fruit fruit = new GoldenDelicious();

Orange orange = new Orange();

回答下面的问题:

a. fruit instanceof Fruit的值为 true 吗?

True

b. fruit instanceof Orange 的值为 true 吗?

False

c.fruit instanceof Apple的值为true吗?

True

d.fruit instanceof GoldenDelicious 的值为 true 吗?

True

e.fruit instanceof Macintosh的值为true吗?

False

f.orange instanceof Orange 的值为 true 吗?

True

g.orange instanceof Fruit 的值为 true 吗?

True

h.orange instanceof Apple 的值为 true 吗?

False

i.假设makeApple Cider方法定义在Apple类中。fruit可以调用这个方法吗?orange可以调用这个方法吗?

都不可以

j.假设makeOrangeJuice方法定义在Orange类中。orange可以调用这个方法吗?fruit可以调用这个方法吗?

orange可以,但是fruit不可以

k.语句 Orange p=new Apple() 是否合法?

不合法

必须要在同一个继承链,才可以进行类型转化

l.语句Macintosh p=new Apple()是否合法?

不合法

需要使用转型括号()来进行转化尝试

m.语句Apple p=new Macintosh()是否合法?

合法

11.27 下面代码中的错误是什么?

public class Test {
   
	public static void main(String[] args) {
   
		Object fruit = new Fruit();
    //Fruit实际上是父类,不能把父类变成子类
		Object apple = (Apple)fruit;
  }
}

class Apple extends Fruit {
   
}

class Fruit {
   
}
11.10章节习题

11.28 每个对象都有 toString 方法和 equals 方法吗?它们从何而来?如何使用?重写这些方法合适吗?

都有,从Object来,使用object1.equals(object2);,非常合适

11.29 当覆盖equals方法时,常见的错误就是在子类中输错它的签名。例如:equals 方法被错误地写成equals(Circle circle) , 如下面a中的代码所示;应该使用如b中所示的 equals(Object circle)替换它。分别给出运行a和b中的Test类和Circle类的输出。

public class Test {
   
  public static void main(String[] args) {
   
		Object circle1 = new Circle();
		Object circle2 = new Circle(); 		
    System.out.println(circle1.equals(circle2));
	} 
}

a:

class Circle {
    
  double radius;

  public boolean equals(Circle circle) {
    
    return this.radius == circle.radius;
	} 
}

输出结果false

b:

class Circle {
    
  double radius;

  public boolean equals(Object circle) {
    
    return this.radius == ((Circle)circle).radius; 
  }
}

输出结果true

如果 Test 类中的 Object 换成 Circle, 那么分别使用 a 和 b 中的 Circle 类来运行 Test 将输出什么?

都是true

11.11章节习题

11.30 如何实现以下功能?

a.创建一个存储双精度值的 ArrayList。

ArrayList<Double> decimals = new ArrayList<>();

b.向数组列表中追加一个对象。

decimals.add();

c.在数组列表的开始位置插人一个对象。

decimals.add(0, 3.14);

d.找出数组列表中所包含对象的个数。

decimals.size();

e. 从数组列表中刪除给定对象。

decimals.remove(3.14);

f. 从数组列表中删除最后一个对象。

decimals.remove(decimals.size() - 1);

g.检测一个给定的对象是否在数组列表中。

decimal.contains(3.14):

h.从数组列表中获取指定下标位置的对象。

decimal.get(1);

11.31 请找出下面代码中的错误:

ArrayList<String> list = new ArrayList<>(); list.add("Denver");
list.add("Austin");
//已经制定了ArrayList的类型是String,就不可以再上传Date
list.add(new java.util.Date());
String city = list.get(0); 
//超过范围了
list.set(3, "Dallas"); 
System.out.println(list.get(3));

11.32 假定ArrayList list包含{“Dallas”,“Dallas”,“Houston”,“Dallas”}。调用list.remove(“Dallas”)—次之后的列表是什么?下面语句可以从列表中删除所有具有值"Dallas"的元素么?如果不能,修改代码。

for (int i = 0; i < list.size(); i++)
	list.remove("Dallas");

如果只调用一次remove,列表会变成{“Dallas”,“Houston”,“Dallas”}

这个语句不可以删除所有Dallas,因为随着不同的Dallas被删除,ArrayList的length是在不断变小的,最后会导致循环提前终止

for (int i = 0; i < list.size(); i++) {
   
  if (list.remove(element))
    i--;
}

11.33 解释为什么下面代码显示[1,3],而不是[2,3]。

ArrayList<Integer> list = new ArrayList<>(); list.add(1);
list.add(2);
list.add(3);
list.remove(1); System.out.println(list);

remove(1)移除的不是数字1,而是在数组中index=1的元素

11.34 解释为什么下面代码是错误的。

ArrayList<Double> list = new ArrayList<>();
list.add(1);

1被当成了整数类型

11.12章节习题

11.35 改正下面语句中的错误:

int[] array = {
   3, 5, 95, 4, 15, 34, 3, 6, 5};
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(array));

//基本数据类型不可以传递给ArrayList,ArrayList中的元素必须是对象
Integer[] array = {
   3, 5, 95, 4, 15, 34, 3, 6
### 回答1: 11.6题要求我们实现一个简单的Java虚拟机,可以执行一些简单的Java程序。具体来说,我们需要实现以下几个部分: 1. 读取Java字节码文件,将其解析成指令序列。 2. 实现一个虚拟机栈,用于存储局部变量和操作数栈。 3. 实现指令集,包括常量加载、算术运算、比较运算、跳转等指令。 4. 执行指令序列,模拟Java程序的执行过程。 在实现过程中,我们需要注意一些细节问题,比如指令的操作数类型、栈帧的管理、异常处理等。此外,我们还需要考虑性能问题,比如如何优化指令的执行速度、如何减少内存占用等。 总之,实现一个Java虚拟机是一项非常复杂的任务,需要深入理解Java语言和计算机系统的原理。但是,通过这个练习,我们可以更好地理解Java程序的执行过程,提高我们的编程能力。 ### 回答2: Java黑皮1111.6主要探讨了Java中的异常处理机制,以及如何自定义异常。本节的核心知识点包括: 1. 异常的概念:异常是在程序执行期间发生的错误或其他意外情况,它打断了正常的程序执行流程。 2. 异常的分类:Java中将异常分为Checked异常和Unchecked异常。Checked异常在编译期间就必须捕获处理,否则编译器会提示错误。Unchecked异常则不需要在编译期间捕获,但程序在运行时会抛出异常。 3. 异常处理机制:Java提供了try-catch语句用于捕获和处理异常。try块中放置可能会抛出异常的代码,catch块中处理异常的代码。 4. 自定义异常:Java允许我们自定义异常类,继承自Exception或RuntimeException,也可以添加自己的字段、方法等。 这一节的课后题主要是通过代码实践来加深对异常处理机制的理解,以及练习自定义异常类。有一道比较经典的题目是编写一个自定义异常类,并在程序中抛出这个异常。这个题目的思路可以参考以下步骤: 1. 创建一个自定义异常类,继承自Exception或RuntimeException。 2. 在构造方法中传入异常信息,然后调用父类的构造方法。 3. 在程序的某个地方,使用throw关键字抛出自定义异常。 4. 在主程序中使用try-catch语句捕获自定义异常,在catch块中处理异常。 例如,我们可以创建一个自定义异常类MyException,并在程序的某个地方抛出这个异常: class MyException extends RuntimeException{ public MyException(String message){ super(message); } } public class Main{ public static void main(String[] args){ try{ throw new MyException("这是一个自定义异常"); }catch(MyException e){ System.out.println("捕获到自定义异常:" + e.getMessage()); } } } 在这个例子中,我们创建了一个自定义异常类MyException,它继承自RuntimeException。在程序的try块中,我们使用throw关键字抛出这个异常。在主程序中,我们使用try-catch语句捕获这个自定义异常,并在catch块中处理异常并输出异常信息。 总的来说,Java黑皮1111.6是一个非常重要的节,掌握异常处理机制和自定义异常类的知识对于Java程序开发至关重要。在实际的开发中,我们需要根据实际情况进行异常处理,使程序更加健壮和可靠。 ### 回答3: 11.6题是要求实现一个基于协程(Coroutine)的简单HTTP服务器。协程是一种比线程更轻量级的并发机制,可以在单个线程中实现多个协程的交替执行,类似于CPU在操作系统中的任务切换。HTTP服务器是指接受HTTP请求并返回HTTP响应的程序或服务。 在实现基于协程的HTTP服务器时,我们需要使用Java的协程库,比如Quasar,ByteBuddy或Kilim。在这个服务器中,每个HTTP请求都被视为一个协程,并且服务器需要实现以下功能: 1. 监听并接受HTTP请求:服务器需要启动一个监听端口,以接受客户端的HTTP请求,并将其转变为协程来处理。 2. 解析HTTP请求:对于每个接受的HTTP请求,服务器需要解析其请求头和主体,以确定请求类型、请求路径、请求方法等信息。 3. 处理HTTP请求:服务器需要根据请求的类型和路径,决定如何处理每个HTTP请求。常见的处理方式是返回文件内容、执行代码、跳转到其它页面等。在协程处理HTTP请求时,服务器可以暂停当前协程,等待文件读取、代码执行等耗时操作完成后,再恢复当前协程继续执行。 4. 返回HTTP响应:服务器需要将处理结果封装成HTTP响应,包括响应头和响应主体内容,并将其发送回客户端。 在实现这个服务器时,需要注意以下几点: 1. Java协程库的选择:Java提供了不同的协程库,每个库有不同的优缺点。要根据实际需求选择适合的协程库,并掌握其基本使用方法。 2. HTTP请求的解析:需要熟悉HTTP协议的请求格式和规范,以正确解析每个请求,并提取需要的信息。 3. 耗时操作的处理:在处理HTTP请求时,可能会遇到需要,等待文件读取、代码执行等耗时操作。要注意在这些操作上暂停当前协程,并在操作完成后恢复协程的执行。 4. 程序的安全性:在实现HTTP服务器时,要注意相关的安全问题,比如防止跨站脚本(XSS)攻击、拒绝服务(DOS)攻击、SQL注入等。 总之,基于协程实现HTTP服务器是一项复杂的工作,需要综合掌握HTTP协议、Java协程库、耗时操作处理、程序安全等多个方面的知识。如果熟练掌握这些技能,就可以实现高效、安全、稳定的HTTP服务器,满足不同场景下的需求。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值