刷题笔记2

java流

刷题笔记2_第1张图片

按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类

  • 节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.
  • 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

JAVA常用的节点流:

  • 文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流。
  • 字符串 StringReader StringWriter 对字符串进行处理的节点流。
  • 数 组 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
  • 管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter对管道进行处理的节点流。

常用处理流(关闭处理流使用关闭里面的节点流)

  • 缓冲流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter  增加缓冲功能,避免频繁读写硬盘。
  • 转换流:InputStreamReader OutputStreamReader 实现字节流和字符流之间的转换。
  • 数据流 DataInputStream DataOutputStream  等提供将基础数据类型写入到文件中,或者读取出来

字节流和字符流:

stream结尾都是字节流,reader和writer结尾都是字符流 两者的区别就是读写的时候一个是按字节读写,一个是按字符。 实际使用通常差不多。 在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流。 只是读写文件,和文件内容无关的,一般选择字节流。

Java泛型

刷题笔记2_第2张图片

泛型仅仅是java的语法糖,它不会影响java虚拟机生成的汇编代码,在编译阶段,虚拟机就会把泛型的类型擦除,还原成没有泛型的代码,顶多编译速度稍微慢一些,执行速度是完全没有什么区别的.

使用泛型的好处

1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。

Java参数传递

刷题笔记2_第3张图片

在Java里,只有值传递,因为引用本身就是一个地址值,我们说的”传递引用“本质上也是“值传递”,只不过传递的是地址值。

 

在方法中,改变一个对象参数的引用不会影响到原始引用。这是很自然的。

举个例子,假设在函数外有 A a = new A();那么引用a指向堆中的一个对象A()。

假设有一个函数:

void f(A a) {

    a = new A();

}

 

显然,这里a指向了堆中的另一个对象A(),而在函数外的那个引用a依然没有改变,指向原来的对象A()。

位运算

刷题笔记2_第4张图片

计算机本身储存的就是补码:

那么10的补码就是10的原码:0000 0000 0000 1010——这是补码,因为现在是计算机在计算

~10的补码就是:1111 1111 1111 0101

~10的反码就是:1111 1111 1111 0100——补码减1

~10的原码就是:1000 0000 0000 1011——反码取反:这个才是正常二进制数,换算为整数为-11

原码才可以对应为正常的整数,补码只有转换为原码才能被正常人类识别。

 

刷题笔记2_第5张图片

已知负数的补码,求负数:

补码-1=反码,反码按位取反=该负数绝对值

已知负数,求负数的补码:

1、负数原码除了符号位,按位取反(不含符号位),加1。

2、负数绝对值的补码(也就是原码),按位取反(含符号位),加1

所以这一题中short a = 0000 0000 1000 0000

强转为byte后,截去高八位 变成 1000 0000 符号位为1,所以为负数,由于计算机存储的是补码,所以就是已知负数

的补码然后求负数的情况

反码:1000 0000 - 1 = 0111 1111

原码:反码按位取反得到 1000 0000,即128(该负数的绝对值),因为是负数,所以结果是-128

(ps:byte中本应该表示“-0”的原码规定为代表-128,有符号的byte类型也就能够表示的范围是-128-127)

刷题笔记2_第6张图片

采用同样的方法: a = 0111 1111      b = 0111 1111

则a和b的补码都是0111 1111(因为两者都为正数),因为计算机计算的时候是用补码计算的,所以

a = 0111 1111 + 0111 1111 = 1111 1110(结果是补码,java中整数都是有符号类型的,所以判定是负数),也就变成上面的已知负数的补码求负数的过程了 反码 = 补码 - 1 = 1111 1101  该负数的绝对值 = 反码按位取反 = 0000 0010 = 2 ,所以结果是-2

即 a = -2,b = 127

run和start

两种方法的区别:

    1.start方法

         用 start方法来启动线程,是真正实现了多线程, 通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法。但要注意的是,此时无需等待run()方法执行完毕,即可继续执行下面的代码。所以run()方法并没有实现多线程。

    2.run方法

         run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码。

Enum枚举

刷题笔记2_第7张图片

枚举类有多少个实例,就会调用多少次构造方法

枚举类构造方法只能加private修饰符(或不加),因为枚举类本身已经是构造好的,不允许再被外部构造

Java的各种变量

刷题笔记2_第8张图片

选B。考察的是类所包含的类型变量。

  • 实例变量:是定义在是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。分配了内存空间后会给所有的成员变量一次初始化,没有赋值的会给成员变量对应类型的值,数据类型不同则默认值不同。所以A正确
  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。用的时候是直接入栈的,如果没有赋值,这个变量就没有初始值,也就无法操作,所以局部变量要初始化所以B错误。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。所以C正确。
  • final变量,final 修饰的变量。如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。所以D正确。

jvm垃圾收集器

刷题笔记2_第9张图片

P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法

Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理

Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法

Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理

Parallel Old(并行)收集器,针对老年代,标记整理

CMS收集器,基于标记清理

G1收集器:整体上是基于标记 整理 ,局部采用复制

 

综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理。
 

Java中的异常

刷题笔记2_第10张图片

异常分为运行时异常,非运行时异常和error,其中error是系统异常,只能重启系统解决。非运行时异常需要我们自己补获,而运行异常是程序运行时由虚拟机帮助我们补获,运行时异常包括数组的溢出,内存的溢出空指针,分母为0等!

运行时异常

ClassCastException(类转换异常)

ClassNotFoundException

IndexOutOfBoundsException(数组越界异常)

NullPointerException(空指针异常)

非运行时异常

IOException

SqlException

ArrayStoreException(数组存储异常,即数组存储类型不一致)

还有IO操作的BufferOverflowException异常

 

静态方法的加载

刷题笔记2_第11张图片

该代码段能编译通过并正常运行

因为Test类的hello方法是静态的,所以是属于类的,当实例化该类的时候,静态会被优先加载而且只加载一次,所以不受实例化new Test();影响,只要是使用到了Test类,都会加载静态hello方法!
另外,在其他类的静态方法中也是可以调用公开的静态方法,此题hello方法是使用public修饰的所以在MyApplication中调用hello也是可以的。
总结:即使Test test=null;这里也会加载静态方法,所以test数据中包含Test类的初始化数据。(静态的,构造的,成员属性)
        因此test.hello是会调用到hello方法的。

 

刷题笔记2_第12张图片

属于被动引用不会出发子类初始化 

 1.子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化 

 2.通过数组定义来引用类,不会触发此类的初始化 

 3.常量在编译阶段会进行常量优化,将常量存入调用类的常量池中, 本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。 

所以答案是

P is init
123

运算符优先级

刷题笔记2_第13张图片

刷题笔记2_第14张图片

Java反射机制

刷题笔记2_第15张图片

普通的java对象是通过new关键字把对应类的字节码文件加载到内存,然后创建该对象的。

反射是通过一个名为Class的特殊类,用Class.forName("className");得到类的字节码对象,然后用newInstance()方法在虚拟机内部构造这个对象(针对无参构造函数)。

也就是说反射机制让我们可以先拿到java类对应的字节码对象,然后动态的进行任何可能的操作,

包括

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

这些都是反射的功能。

使用反射的主要作用是方便程序的扩展。

刷题笔记2_第16张图片

当一个类或接口被加载到JVM的时候便会产生一个与之关联的一个Java.lang.Class对象,我们可以通过此Class对象来得到被装入的类的详细信息。

其中:

Method[] getDeclaredMethods() 返回 Class 对象表示的类或接口的所有已声明的方法数组,但是不包括从父类继承和接口实现的方法。

Method[] getMethods() 返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承或实现接口的方法。

字符集编码

刷题笔记2_第17张图片

A 显然是错误的,Java一律采用Unicode编码方式,每个字符无论中文还是英文字符都占用2个字节。

B 也是不正确的,不同的编码之间是可以转换的,通常流程如下:

将字符串S以其自身编码方式分解为字节数组,再将字节数组以你想要输出的编码方式重新编码为字符串。

例:String newUTF8Str = new String(oldGBKStr.getBytes("GBK"), "UTF8");

C 是正确的。Java虚拟机中通常使用UTF-16的方式保存一个字符(Java的class文件编码为UTF-8,而虚拟机JVM编码为UTF-16)

D 也是正确的。ResourceBundle能够依据Local的不同,选择性的读取与Local对应后缀的properties文件,以达到国际化的目的。

综上:答案是C、D

集合遍历方式的删除

刷题笔记2_第18张图片

该段程序会抛异常,原因如下:

对于集合的三种遍历方式删除:

1.普通for循环:可以删除

        注意每次删除之后索引要--

2.Iterator遍历:可以删除

        不过要使用Iterator类中的remove方法,如果用List中的remove方法会报错

3.增强for循环foreach:不能删除

        强制用List中的remove方法会报错

 

 

你可能感兴趣的:(java)