Java基本知识

一、I/O

分字节流和字符流

字节流由InputStream和OutputStream读入和写入

DataInputStream继承自FilterInputStream,可以读取基本数据类型(char, byte, short, int, long, double, float, boolean)和String类型

字符流有FileReader,FileWriter,StringReader,StringWriter,CharArrayReader,CharArrayWriter,BufferedReader和BufferedWriter

InputStreamReader可以把InputStream转化为Reader,而OutputStreamReader可以把OutputStream转化为Writer。

二、如何使用DataInputStream

Socket socket;

DataInputStream in = new DataInputStream( new BufferedInputStream( socket.getInputStream() ) );

in.readByte(); in.readUTF();

三、标准I/O重定向

Java的System类提供一些简单的静态方法调用,允许我们对标准I/O和错误I/O流进行重定向:

SetIn(InputStream)

SetOut(PrintStream)

SetErr(PrintStream)

I/O重定向操作的是字节流而不是字符流,因此我们是用InputStream和OutputStream而不是Reader和Writer

四、NIO

NIO与I/O最重要的区别是数据打包和传输的方式。原来的I/O以流的方式处理数据,而NIO以块的方式处理数据。

面向流的I/O系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的I/O 通常相当慢。

面向块的I/O系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的I/O缺少一些面向流的I/O所具有的优雅性和简单性。

通道和缓冲区是NIO中的核心对象,几乎在每一个I/O操作中都要使用它们。所有数据都通过Buffer对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类), 而Channel可以用于读、写或者同时用于读写。因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在 UNIX 模型中,底层操作系统通道是双向的。

Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。

NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

了解了这个基本原理,我们结合代码看看使用,在使用上,也在分两个方向,一个是线程处理,一个是用非线程,后者比较简单。

五、Java如何存储数据

  1. Register,这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是Register的数量极其有限,所以Register由编译器根据需求进行分配。你不能直接控制.Stack,位于通用RAM中。
  2. Heap,用于存放所有Java对象.
  3. 静态存储
  4. 常量存储
  5. 非RAM存储,例如流对象和持久化对象

JVM只能回收Heap中的内容

六、Primitive Type

Primitive type

Size

Minimum

Maximum

Wrapper type

char

16bits

Unicode 0

Unicode 215-1

Character

byte

8bits

-128

127

Byte

short

16 bits

-215

215-1

Short

int

32 bits

-231

231-1

Integer

long

64 bits

-263

263-1

Long

float

32 bits

 

 

Float

double

64 bits

 

 

Double

boolean

 

 

 

 

七、Java为什么可以移植

Java每种基本数据类型所占存储空间大小不随硬件架构变化而变化.

八、将float或者double值转成整型值后,总是将小数部分砍掉,而不是四舍五入。Math.random()范围为[0,1)。

九、java类加载原理和过程

java中默认有三种类加载器:启动类加载器,扩展类加载器,系统类加载器(也叫应用类加载器)。

启动类加载器bootstrap负责加载jre/lib中的系统类,这种类加载器都是用c语言实现的,在java程序中没有办法获得这个类加载器,对于java程序是一个概念而已,基本上不用考虑它的存在,像String,Integer这样的类都是由启动类加载器加载器的。

扩展类加载器ExtClassLoader负责加载jre/lib/ext中的类,一般使用java实现,这是一个真正的java类加载器,和普通的类加载器一样,其实这个类加载器对我们来说也不是很重要,我们可以通过java程序获得这个类加载器。

系统类加载器AppClassLoader加载第一个应用类的加载器(其实这个定义并不准确,下面你将会看到),也就是执行java MainClass 时加载MainClass的加载器,这个加载器使用java实现,使用的很广泛,负责加载classpath中指定的类。

类加载器之间有一定的关系(父子关系),我们可以认为扩展类加载器的父加载器是启动类加载器(当然不这样认为也是可以的,因为启动类加载器表现在java中就是一个null),不过系统类加载器的父加载器一定是扩展类加载器,类加载器在加载类的时候会先给父加载器一个机会,只有父加载器无法加载时才会自己去加载。

在ClassLoader.java(ExtClassLoader和AppClassLoader的间接父类)中的loadClass(name)首先在内存中查找该类是否被load进来了,如果没有load进来则依双亲委派原则进行查找,你的类装载器首先将请求传递给它的双亲类装载器,然后将这个请求一路委派直到委派给启动类装载器。则启动类装载器可以将java.ang.String类返回给你的类装载器,因为启动类装载器可以找到这个类,所以就不必在扩展类装载器中查找了,否则将在扩展类装载器查找,如果再找不到就在系统类装载器查找,如果系统类装载器也找不到就试图从网络下载这个类。不同类装载器中的类不能访问彼此的包内可见成员。另外说明一点,包名不能以java.开头,否则会抛出SecurityException。

十、类实例化途径 

  1. New
  2. 调用Class或者java.lang.reflect.Constructor对象的newInstance()
  3. 调用任何对象的clone()
  4. 通过java.io.ObjectInputStream的getObject()反序列化

十一、ConcurrentHashMap底层实现

 pasting

十二、Volatile

十三、

十四、

pasting

 

pasting

 

posted @ 2016-03-24 10:57  风雪夜归猿  阅读(206)  评论(0编辑  收藏  举报