Java学习记录——错题总结(九)

第一套

1.java中下面哪个能创建并启动线程()

public class MyRunnable implements Runnable { 
     public void run() { 
         //some code here 
     } 
 }

正确答案: C
new Runnable(MyRunnable).start()
new Thread(MyRunnable).run()
new Thread(new MyRunnable()).start()
new MyRunnable().start()

C正确
首先:创建并启动线程的过程为:定义线程—》实例化线程—》启动线程。
一 、定义线程: 1、扩展java.lang.Thread类。 2、实现java.lang.Runnable接口。
二、实例化线程: 1、如果是扩展java.lang.Thread类的线程,则直接new即可。
2、如果是实现了java.lang.Runnable接口的类,则用Thread的构造方法:
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
所以A、D的实例化线程错误。
三、启动线程: 在线程的Thread对象上调用start()方法,而不是run()或者别的方法。
所以B的启动线程方法错误。

2.关于下列程序段的输出结果,说法正确的是:( )

public class MyClass{
    static int i;
    public static void main(String argv[]){
        System.out.println(i);
    }
}

正确答案: D
有错误,变量i没有初始化。
null
1
0

类变量在不设置初始值时,会进行默认值赋值,而局部方法中声明的变量则必须进行初始化,他不会进行默认值赋值。

3.以下代码执行的结果显示是多少( )?请添加图片描述
正确答案: D
true,false,true
false,true,false
true,true,false
false,false,true

当我们给一个Integer赋予一个int类型的时候会调用Integer的静态方法valueOf。
Integer f1 = Integer.valueOf(100);
Integer f2 = Integer.valueOf(100);
Integer f3 = Integer.valueOf(150);
Integer f4 = Integer.valueOf(150);
思考:那么Integer.valueOf()返回的Integer是不是是重新new Integer(num);来创建的呢?如果是这样的话,那么== 比较返回都是false,因为他们引用的堆地址不一样。

具体来看看Integer.valueOf的源码

public static Integer valueOf(int i) {
         
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.***[i + (-IntegerCache.low)];
        return new Integer(i);
}

在IntegerCache中***数组初始化如下,存入了-128 - 127的值

*** = new Integer[(high - low) + 1];
int j = low;
for( int k = 0; k < ***.length ; k ++)
    ***[k] =
    ***[k] = new Integer(j ++);

从上面我们可以知道给Interger 赋予的int数值在-128 - 127的时候,直接从***中获取,这些***引用对Integer对象地址是不变的,但是不在这个范围内的数字,则new Integer(i) 这个地址是新的地址,不可能一样的.

简单来说就是在-128到127的范围是相同的,但是不在这个范围则会默认调用new Integer

第二套

1.10. class Line {
11. public class Point { public int x,y;}
12. public Point getPoint() { return new Point(); }
13. }
14. class Triangle {
15. public Triangle() {
16. // insert code here
17. }
18. }
在第16行插入哪段代码可以获得一个Point对象的坐标?( )
正确答案: D
Point p = Line.getPoint();
Line.Point p = Line.getPoint();
Point p = (new Line()).getPoint();
Line.Point p = (new Line()).getPoint();

因为Point 在 类 Line 里面,属于内部类,直接 使用 Point p 肯定报错。而public class Point { public int x,y;} 是 Point 的构造方法, Line 肯定不能 获取到,Point只能获取到其Class Class c =Line.Point.class;但是如果是 private class Point , Line.Point 将报错不到
对象,只能通过getPoint() ,而 getPoint 不是静态方法,所以需要new Line ,选择最后一个选项

(1)把类定义在另一个类的内部,该类就被称为内部类。 举例:把类B定义在类A中,类B就被称为内部类。 (2)内部类的访问规则
A:可以直接访问外部类的成员,包括私有 B:外部类要想访问内部类成员,必须创建对象 (3)内部类的分类 A:成员内部类 B:局部内部类
C:匿名内部类 (4)成员内部类访问规则 成员内部类不是静态的: 外部类名.内部类名 对象名 = new 外部类名().new
内部类名(); 成员内部类是静态的: 外部类名.内部类名 对象名 = new 外部类名.内部类名(); (5)局部内部类
A:局部内部类访问局部变量必须加final修饰。 B:为什么呢? 因为局部变量使用完毕就消失,而堆内存的数据并不会立即消失。
所以,堆内存还是用该变量,而改变量已经没有了。 为了让该值还存在,就加final修饰。
通过反编译工具我们看到了,加入final后,堆内存直接存储的是值,而不是变量名。 (6)匿名内部类(掌握) A:是局部内部类的简化形式
B:前提 存在一个类或者接口 C:格式: new 类名或者接口名() { 重写方法; } D:本质:
其实是继承该类或者实现接口的子类匿名对象

2.下列关于异常的说法,正确的是()
正确答案: A
RuntimeException及其子类的异常可以不做处理
Catch段中的语句,不允许再次出现异常
在方法定义中以throws标识出的异常,在调用该方法中的方法必须处理
程序中所有的可能出现的异常必须在catch中捕获,否则将引起编译错误

异常分为两种,一种为运行异常RuntimeException,另一种为检查异常CheckedException。
对于运行异常,编译器没有强制对其进行捕获。会把异常一直往上层抛出,直到遇到处理代码为止。常见的运行异常有:nullpointexception(空指针异常),indexoutofboundexception(越界异常)。。。。。
检查异常,所有继承自Exception并且不是运行异常的都是检查异常,在程序中需要用try catch进行捕获。常见的有IO异常和SQL异常。

3.知识点
一般有两种用于创建线程的方法,一是(),二是()。

  1. 从Java.lang.Thread类派生一个新的线程类,重写它的run()方法

  2. 实现Runnable接口,重写Runnable接口中的run()方法

4.有关finally语句块说法正确的是( )
正确答案: A B C
不管catch是否捕获异常,finally语句块都是要被执行的
在try语句块或catch语句块中执行到System.exit(0)直接退出程序
finally块中的return语句会覆盖try块中的return返回
finally 语句块在 catch语句块中的return语句之前执行

结论:
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

第三套

Test.main()函数执行后的输出是( )

class Test {
    public static void main(String[] args) {
        System.out.println(new B().getValue());
    }
    static class A {
        protected int value;
        public A (int v) {
            setValue(v);
        }
        public void setValue(int value) {
            this.value= value;
        }
        public int getValue() {
            try {
                value ++;
                return value;
            } finally {
                this.setValue(value);
                System.out.println(value);
            }
        }
    }
    static class B extends A {
        public B () {
            super(5);
            setValue(getValue()- 3);
        }
        public void setValue(int value) {
            super.setValue(2 * value);
        }
    }
}

正确答案: B ·
6 7 7
22 34 17
22 74 74
11 17 34

思考和解决这个题的主要核心在于对java多态的理解。个人理解时,执行对象实例化过程中遵循多态特性 ==> 调用的方法都是将要实例化的子类中的重写方法,只有明确调用了super.xxx关键词或者是子类中没有该方法时,才会去调用父类相同的同名方法。

Step 1: new B()构造一个B类的实例
此时super(5)语句调用显示调用父类A带参的构造函数,该构造函数调用setValue(v),这里有两个注意点一是虽然构造函数是A类的构造函数,但此刻正在初始化的对象是B的一个实例,因此这里调用的实际是B类的setValue方法,于是调用B类中的setValue方法 ==> 而B类中setValue方法显示调用父类的setValue方法,将B实例的value值设置为2 x 5 = 10。
紧接着,B类的构造函数还没执行完成,继续执行setValue(getValue()- 3) // 备注1语句。

先执行getValue方法,B类中没有重写getValue方法,因此调用父类A的getValue方法。这个方法比较复杂,需要分步说清楚:

调用getValue方法之前,B的成员变量value值为10。
value++ 执行后, B的成员变量value值为11,此时开始执行到return语句,将11这个值作为getValue方法的返回值返回出去
但是由于getValue块被try finally块包围,因此finally中的语句无论如何都将被执行,所以步骤2中11这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
这里有很重要的一点:finally语句块中 this.setValue(value)方法调用的是B类的setValue方法。为什么?因为此刻正在初始化的是B类的一个对象(运行时多态),就像最开始第一步提到的一样(而且这里用了使用了this关键词显式指明了调用当前对象的方法)。因此,此处会再次调用B类的setValue方法,同上,super.关键词显式调用A的setValue方法,将B的value值设置成为了2 * 11 = 22。
因此第一个打印项为22。
finally语句执行完毕 会把刚刚暂存起来的11 返回出去,也就是说这么经历了这么一长串的处理,getValue方法最终的返回值是11。
回到前面标注了 //备注1 的代码语句,其最终结果为setValue(11-3)=>setValue(8)
而大家肯定也知道,这里执行的setValue方法,将会是B的setValue方法。 之后B的value值再次变成了2*8 = 16;

Step2: new B().getValue()
B类中没有独有的getValue方法,此处调用A的getValue方法。同Step 1,

调用getValue方法之前,B的成员变量value值为16。
value++ 执行后, B的成员变量value值为17,此时执行到return语句,会将17这个值作为getValue方法的返回值返回出去
但是由于getValue块被try finally块包围而finally中的语句无论如何都一定会被执行,所以步骤2中17这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
finally语句块中继续和上面说的一样: this.setValue(value)方法调用的是B类的setValue()方法将B的value值设置成为了2 * 17 = 34。
因此第二个打印项为34。
finally语句执行完毕 会把刚刚暂存起来的17返回出去。
因此new B().getValue()最终的返回值是17.
Step3: main函数中的System.out.println
将刚刚返回的值打印出来,也就是第三个打印项:17

最终结果为 22 34 17。 如果朋友们在看的过程中仍然有疑问,可以亲自把代码复制进去ide,在关键语句打下断点,查看调用方法的对象以及运行时的对象值,可以有更深刻的理解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为一个AI语言模型,我无法编写完整的Java应用程序,但我可以给你一些指导,希望能帮到你。 首先,你需要确定你的错题本App需要包含哪些功能。以下是一个简单的功能列表: 1. 用户登录和注册 2. 添加题目和答案 3. 查看错题列表 4. 删除错题 5. 修改错题 6. 退出登录 接下来,你需要设计数据库表结构。你可以使用MySQL或其他数据库管理系统来存储数据。以下是一个简单的数据库表结构: 1. 用户表:包含用户ID、用户名和密码 2. 题目表:包含题目ID、题目、答案和用户ID 3. 错题表:包含错题ID、题目ID和用户ID 然后,你需要编写Java代码来实现上述功能。以下是一个简单的代码示例: 1. 用户登录和注册: ``` // 登录 public boolean login(String username, String password) { // 根据用户名和密码查询用户表 // 如果查询到了用户记录,返回true,否则返回false } // 注册 public boolean register(String username, String password) { // 插入新用户记录到用户表 // 如果插入成功,返回true,否则返回false } ``` 2. 添加题目和答案: ``` public boolean addQuestion(String question, String answer, int userId) { // 插入新题目记录到题目表 // 如果插入成功,返回true,否则返回false } ``` 3. 查看错题列表: ``` public List<Question> getWrongQuestions(int userId) { // 根据用户ID查询错题表和题目表,返回错题列表 } ``` 4. 删除错题: ``` public boolean deleteWrongQuestion(int wrongQuestionId) { // 根据错题ID删除错题记录 // 如果删除成功,返回true,否则返回false } ``` 5. 修改错题: ``` public boolean updateWrongQuestion(int wrongQuestionId, String question, String answer) { // 根据错题ID更新题目表的题目和答案 // 如果更新成功,返回true,否则返回false } ``` 6. 退出登录: ``` public void logout() { // 清除用户登录状态 } ``` 最后,你需要将这些代码整合到一个Java应用程序,并使用Java Swing或其他UI框架来实现用户界面。你还需要编写一些单元测试来确保你的代码能够正确地处理各种情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值