day33周一总结_chap-javase阶段测试_1.加载类概念不清2.线程理解不到位[简答题]

二【读程序题】(2分 x 10)

21如下程序打印的结果是什么呢?

(注:答案包括编译失败 或运行异常。请说明结果的同时注明原因,下面同上)

String str1 = "hello";
String str2 = “he”;
System.out.println(str1.compareTo(str2));

解答:

输出3。

按照String类compareTo的源码,这两个字符串比较的结果应该是str1.length() - str2.length()的结果

 

22. 如果在同包的某个main方法中运行Father father = new Son(1000),程序的输出结果是什么?

Father和Son定义如下

class Father {
    int i = 10;
    public Father() {
        System.out.println(getI());
    }
    public int getI() {
        return i;
    }
}
class Son extends Father {
    int i = 100;
    public Son(int i) {
        this.i = i;
    }
    public int getI() {
        return i;
    }
}

解答:

打印结果为0。

父类方法被子类覆盖,即使在父类中调用,调用到的也是子类方法,而此时父类对象还在初始化过程中,子类对象更是还未开始初始化,其成员变量的值还是默认值。

 

 

23.如下程序打印的结果是什么呢?

public class InTheLoop {
    public static final int END = Integer.MAX_VALUE;
    public static final int START = END - 100;
    public static void main(String[] args) {
        int count = 0;
        for (int i = START; i <= END; i++)
            count++;
        System.out.println(count);
   }

}

解答:

程序无限循环

i的值从Integer.MAX_VALUE-100开始,每次自增1,直到Integer.MAX_VALUE

然后继续自增1变成了Integer.MIN_VALUE(溢出),接着继续自增

直到Integer.MAX_VALUE,并重复。

所以打印的值count,从1开始一直到Integer.MAX_VALUE

然后从Integer.MIN_VALUE到Integer.MAX_VALUE

如此周而复始的打印

 

24. 如下程序打印的结果是什么呢?

public class AnimalFarm{
    public static void main(String[] args){
        final String pig = "length: 10";
        final String dog = "length: " + pig.length();
        System.out. println("Animals are equal: " + pig == dog);
    }
}

解答:

false  

先拼接"Animals are equal: " +  pig得到新的字符串,然后再比较==

 

25. 如下程序打印的结果是什么呢?

public class Bark {
    public static void main(String args[]) {
        Dog woofer = new Dog();
        Dog nipper = new Basenji();
        woofer.bark();
        nipper.bark();
     }
}

class Dog {
    public static void bark() {
        System.out.print("woof ");
    }
}

class Basenji extends Dog {     
    public static void bark() {
    }
}

解答:

woof woof 

静态方法不能被覆盖,所以两次方法调用实际上调用的都是父类,Dog类中定义的静态方法,所以输出两次woof
 

26. 如下程序打印的结果是什么呢?

public class Indecisive {
    public static void main(String[] args) {
        System.out.println(decision());
    }

    static boolean decision() {
        try {
            return true;
        } finally {
            return false;
        }
    }
}

解答:

False

a. 执行第一条return语句的时候,首先将待返回的结果,复制到该方法栈帧中的一个特殊位置。

b. 紧接着,执行finally代码块中的return语句,又将该return语句待返回的值,放到栈帧中,用来存放方法返回值的那个特殊位置(将第一个return语句存放的待返回结果覆盖掉)

c. 然后继续执行第二个return语句,结束方法执行,带着存储在栈帧中特殊位置的那个返回值,返回到方法调用处
 

27. 如下程序打印的结果是什么呢?

public class Test{
    public static void main(String[]args) {
        int[]x={0,1,2,3};
        for(int i=0;i<3;i+=2) {
            try{
                system.out.println(x[i+2]/x[i]+x[i+1]);
            }catch(ArithmeticException e){
                System.out.println("errorl");
            }catch(Exception e){
                System.out.println("error2");
            }
        }
    }
}

解答:

error1

error2

a. 当i值为0时,执行第一次for循环,此时try块中输出语句中输出的计算表达式是在   求 2 / 0 + 1,很显然,发生除0异常,输出error1

b. 紧接着执行第二次循环,此时i值为2,try块的输出语句中计算的是 x[4] / x[2] + x[3], 此时x[4]数组越界,于是输出error2
 

28. 如下程序打印的结果是什么呢?

public class TestMain {
    static {
         System.out.println("C");
    }
    
    {
         System.out.println("B");
    }
    
    public  TestMain(){      
        System.out.println("A");
    }
    
    public static void main(String[] args) {
        TestMain testMain = new TestMain();    
    }
}

解答:

C

B

A

静态代码块先于构造代码块,构造代码块先于构造方法

 

29. 如下程序打印的结果是什么呢?

public class Bground  extends Thread{
    public static void main(String[] args){
        Bground bground=new Bground();
        bground.run();
    }
      
    public void start(){
        for (int i = 0; i < 10; i++) {
            System.out.println("B ground.start()"+i);
            }
    }
}

解答:

正常结束没有任何输出

a. 因为在Thread子类中,没有覆盖父类的run方法,而是覆盖了父类的start()方法

b. 所以,在Thread子类对象上调用的run方法,实际是Thread类中定义的run方法

而根据Thread类的run方法源码,什么都不会输出

 

30. 如下程序打印的结果是什么呢?

public class Reluctant {

    private Reluctant internalInstance = new Reluctant();

    public Reluctant() throws Exception {
        throw new Exception("I'm not coming out");
    }

    public static void main(String[] args) {
        try {
            Reluctant b = new Reluctant();
            System.out.println("Surprise!");
        } catch (Exception ex) {
            System.out.println("I told you so");
        }
    }

}

解答:

Stackoverflow error

a. 首先,执行main方法中的创建对象的语句Reluctant b = new Reluctant();

b. 但是,在创建对象的过程中,会执行成员变量的初始化语句

private Reluctant internalInstance = new Reluctant();

于是又会创建Reluctant对象,于是又执行a,a执行完了,又执行b... 如此周而复始

c. 于是,就出现了一个递归。

 

三【简答题】(2分 x 10)

31. 引用类型和基本数据类型有何区别?

解答:

基本数据类型包括:byte,short,char, int,long,float,double,boolean

引用数据类型主要包括:类,接口等

基本数据类型的变量存储的是该类型变量的值,而引用数据类型的变量存储的是地址(比如堆中对象的地址)

 

32. java中父类中定义的哪些方法没有多态效果,为什么?

解答:多态发生的条件是

1)继承

2)方法覆盖

3)父类引用指向子类实例

所以哪些方法(行为),实现不了多态效果——不能在子类中被覆盖的方法

a. 父类中的private方法(不能被子类覆盖)
b. 父类中的构造方法(不能被子类继承)
c. 父类中的静态方法(不能被子类覆盖)
d. 父类中被final修饰的方法(不能被子类覆盖)
 

 

33. 如何理解静态上下文无法访问非静态的成员变量和成员方法?

解答:

静态上下文不能访问非静态的成员变量或成员方法其实是指

在静态上下文中,无法访问,当前对象this的成员变量;

或在当前对象this上调用其非静态的成员方法。

因为对于静态上下文而言,静态的东西都是不依赖于对象而存在,所以当静态上下文被访问的时候,当前对象可能并不存在,所以自然无法访问。

 

34. 方法重载和方法重写的区别。

解答:

重载是指在同一个类中定义同名方法,而这些方法名称相同,但方法签名不同。方法重写,是指在子类中,修改父类中定义的方法的实现。

因此,他们发生的范围是不同的,方法重载发生在一个任意类中,而方法重写,发生在子类中,而且发生方法重写和方法覆盖的条件也不相同(这里不再赘述)

同时,方法重载是编译时多态,而方法重写是运行时多态的前提条件之一
 

 

35. "=="和equals方法有何异同?

解答:

== 对于基本数据类型的数据而言,比较的是内容,对于引用数据类型的数据而言,比较的引用变量,所指向的内存地址。equals方法是Object类的方法,其默认实现是比较两个对象的内存地址是否相同

若想要比较量对象的内容是否相同,则需要在子类中覆盖Object的equals方法
 

 

36. 字符流和字节流最主要的区别是什么?如何理解字符流=字节流+编码表?

解答:

节流和字符流的流中数据的逻辑单位不同。

字节流中数据的逻辑单位:二进制的字节数据

字符流中数据的逻辑单位:单个字符

a)字符数据在内存中还是以二进制(字符的在编码表中对应的编码值)的形式保存和传输
b)而对于二进制的字节数据的写和读,字节流就已经能够很好的完成了
c) 但为了保证字符流中的数据是一个一个的完整字符,所以字符流在字节流的基础上,添加了编解码器,即在使用底层字节流写数据前,先利用编码器,对字符数据进行编码得到字符数据对应的二进制编码序列,然后利用底层字节流传输它们,同时,在读取数据的时候,先用解码器,将由底层字节流传输的字节数据,解码成一个一个的字符

所以字符流的功能实现是字节流 + 编码表(基于编码表的编解码操作)
 

 

37.使用缓冲流是否可以在一定程度改善应用程序的IO的效率?为什么??

解答:

可以从一定程度上改善Java程序的IO效率。因为,IO的底层实现,是要依靠操作系统内核的功能来实现的,而我们的java程序每次请求操作系统内核的功能完成IO的时候,都需要付出额外的代价。既然,每次完成IO操作,都需要付出一次通信代价,那么意味着,一次IO操作如果读写的数据越多,那么平均到每个字节(字符)的数据,所付出的额外代价就会越小。   
而缓冲流,本身维护了一个较大的缓冲区,能够在和操作系统内核交互的过程中,一次读写较多的字节(字符)数据,从而在整个数据传输过程中,减少java程序和操作系统内核通信的次数。从而减少了,应用程序为了完成功能,所需要付出的额外代价
 

 

38. 同步和异步有何异同,在什么情况下分别使用他们?

解答:

异步:线程之间,各自独立运行,互不影响。线程之间“同时”,在各自做自己的事情,简单来说,就是我走你也走
同步:和异步相对。同步是指线程之间不能再各自为政,自己运行自己的,而是在某些情况下等待其他线程。简单来说,就是我走你不走

线程天生就是异步执行的,而当多线程异步访问同一个共享数据的时候,为了保证共享数据访问的正确性,必须保证同时只有一个线程,能访问并修改共享变量的值,这意味着,如果一个线程正在,访问某共享变量,则其他所有要访问该共享变量的线程都需要等待,直到,该线程访问完毕。
 

 

39. Java语言多线程设计中,为什么wait, notify 和 notifyAll这些线程通信的方法不在thread类里面?

解答:

线程通信,其实是依靠锁对象,来完成的(对于wait方法而言,调用wait方法的对象,首先必须被当前线程,作为锁对象持有),而java语言中的锁对象,可以是任意对象,因此这些方法被定义在Object中

 

40. Java多线程中调用wait() 和 sleep()方法有什么不同?

解答:

sleep方法的唤醒条件是时间,而wait()方法的唤醒条件是,必须被在同一个锁对象上调用notify()或notifyAll()方法。

sleep方法是Thread类的静态方法,而wait()方法是Object类的方法

sleep方法在导致当前线程休眠时,当前线程不会释放所有有的锁,而wait()方法导致当前线程休眠时,当前线程会释放锁对象

 

四.【编程题】(10分 x 2)

41. 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

比如,如果数组是[1, 2, 3]则加1之后的结果是[1, 2, 4], 如果数组是[1, 2, 9]加1之后的结果就是[1, 3, 0]

解答:

第一题,给参考代码如下

public class Solution {
    public int[] plusOne(int[] digits) {
        
        //从后往前遍历,因为加法运算从右往左加,低位到高位
        for (int i = digits.length - 1; i >= 0; i--) {
            //对第i位上的数字值+1
            digits[i]++;
            //求+1之后,该位上的数字
            digits[i] = digits[i] % 10;
            //若低位没有进位,则高位的数字都不变直接返回
            if (digits[i] != 0) {
                return digits;
            }
        }
        //否则,意味着 +1 之后,原数多了一位
        //此时只有一种情况,就是99...9这种
        //+1之后的结果,稚嫩格式最高位为1,其余个位都为0
        digits = new int[digits.length + 1];
        digits[0] = 1;
        return digits;
    }
}

该题目,其实有对应的o(n)时间复杂度的实现,即一次遍历,得到结果

这种实现方式只是比较好理解,并非最简

用双重循环,只要能写出代码,也是算正确,不要求所有人掌握

至少必须会用双重循环解这道题(起码能实现基本功能,暴力破解)

核心思想:对于任意一个连续子数组,如果其前面的部分和已经  <0, 那就不用再对该子数组继续向后累加,因为负数 + 后面部分的和只会使得后面部分的和越小

出现子数组和 <0 这种情况,一定是因为刚刚累加用的是负数

因此,新的子数组,从该负数的下一个位置开始计算(因为只要不跳过该负数,那么该负数前面部分的和,跟该负数相加,所得的结果一定还是负数)

 

42. 输入一个整型数组,数组里面有正数也有负数,数组中连续的一个或多个整数组成子数组,每个子数组都有一个和。求所有子数组的和的最大值。例如,输入的数字为:1,-2,3,10,-4,7,2,-5,则和最大的子数组为3,10,-4,7,2和为18

解答:

public static int maxSequentialSum(int[] array) {
        //max存储最大的连续子数组的和
        int max = array[0];
        //存储当前遍历的连续子数组的和
        int currentSum = array[0];
        for (int i = 1; i < array.length; i++) {
            if (currentSum < 0) {
                //如果当前连续子数组的和已经 <0
                //那么对于当前子数组而言,再累加下去没有意义

                //原因:
                //   和一个负数累加,只会使得后面部分的和变小
                //因此,这个数组不再计算,取新数组计算
                //
                
                //同时,之所以会出现当前子数组之和 <0,一定是上次累加用的是负数
                //所以要跳过该负数,然后构建新数组
                //新的子数组从第 i 个位置开始,刚才累加的是第 i-1 个位置的元素
                
                currentSum = array[i];
            } else {
                //否则,继续向后累加当前的连续子数组的和
                currentSum += array[i];
            }
            
            if (currentSum > max) {
                //如果当前子数组之和,比之前存在的最大子数组之和更大
                max = currentSum;
            }
        }
        //走到这里遍历完成
        //max就是所有子数组和中最大的
        return max;
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值