JVM :运行Java程序的虚拟机。为了能使用相同的字节码得出相同的结果,对于不同的系统JVM具有不同的特定实现。
JDK与JRE
JRE : Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。
JDK(Java Development Kit) :它是功能齐全的 Java SDK。它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。它能够创建和编译程序。
字节码 :JVM可以理解的代码(即扩展名为.class),不面向任何特定的处理器,只面向虚拟机。
采用字节码的好处 :Java通过字节码解决了解释型语言执行效率低的问题且保留了可移植性、使Java程序无需重新编译即可在不同的操作系统中运行。
Java查询从源码到运行的过程 : 源码(.java)经过javac编译变成字节码(.class)然后通过解释器变成机器码,最后运行。
按照高级编程语言的程序执行方式可将其分为两类 :
编译型 :通过编译器将源代码一次性翻译成可被该平台执行的机器码。(开发效率低,执行快)
解释型 :通过解释器一句一句的将代码解释为机器码后再执行(开发效率高,执行慢)
包含有 :单行注释、多行注释和文档注释。
由JAVA语言赋予了特殊含义的标识符,只能用于特定的地方。简单的说就是被赋予了特殊含义的名字。
常见关键字
三种程序控制关键字的作用:
continue :指跳出当前的这一次循环,继续下一次循环。
break :指跳出整个循环体,继续执行循环下面的语句。
return 用于跳出所在方法,结束该方法的运行。
return 一般有两种用法:
1、return; :直接使用 return 结束方法执行,用于没有返回值函数的方法
2、return value; :return 一个特定值,用于有返回值函数的方法
Java泛型是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
类型擦除 :Java 的泛型是伪泛型,这是因为 Java 在运行期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。
泛型的三种使用方式 :泛型类、泛型接口、泛型方法。
常用的通配符:T、E、K、V、?
== 在作用于基本数据类型和引用类型的效果是不同的:
==的本质其实就是值的对比,而导致两种情况不同的原因是引用类型的值是对象的地址。
equals()不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。(equals方法是在Object类中)
public boolean equals(Object obj){
return (this==obj)
}
//Object类中的源码
从上面的源码我们可以看出来在该方法没有被子类覆盖的情况下,就是利用==进行的比较。
而一般情况下都会被覆盖 然后利用该方法来判断两个对象中的属性是否相等。
覆盖的情况 比如String ,String中就是通过覆盖了根类Object的equals()方法,使得该方法变成了判断两个对象的值是否相等。
Hashcode()
它的作用是获取哈希码(int 整型),也被称为散列码,而散列码的作用是确定对象在哈希表中的索引位置。同样Hashcode()也是Object类中的方法且为本地方法,也就是c/c++写的。并且默认情况下它是通过将对象的内存地址转换为整数之后返回的。
这里需要解释的是equals()和hashcode()只在使用到hashset等本质是散列表的数据结构时才会有联系,在其它情况下是没有联系的
当你把对象加入
HashSet
时,HashSet
会先计算对象的hashcode
值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode
,HashSet
会假设对象没有重复出现。但是如果发现有相同hashcode
值的对象,这时会调用equals()
方法来检查hashcode
相等的对象是否真的相同。如果两者相同,HashSet
就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。。这样我们就大大减少了equals
的次数,相应就大大提高了执行速度。
当有联系时,也就是需要用到散列表时,我们必须满足一些条件
也就是说如果equals()被覆盖,hashcode()也必须被覆盖。这是因为默认的equals是通过==来进行比较,所以如果对象的内存地址不一样那么就不会相等,同样hashcode的默认也是通过将内存地址转换成int来返回的,所以在默认情况下,只要equals()相等,hashcode就一定会相等。但是如果equals()被覆盖,就比如String类,它是通过对象的值进行比较的,所以就算两个对象的内存地址不同,只要值相等equals()也是相等的,而这种情况下如果不覆盖hashcode()那么 hashcode()就会不相等。所以覆盖equals()就必须覆盖hashcode()。
但是为什么会出现hashcode相等 而equals()不相等的情况呢? 这就与hashcode使用的哈希算法有关了,如果哈希算法不够好,就会容易产生hashcode的碰撞,所谓碰撞就算hashcode相等。
基本类型 | 位数 | 字节 | 默认值 | 对应包装类 |
---|---|---|---|---|
int |
32 | 4 | 0 | Integer |
short |
16 | 2 | 0 | Short |
long |
64 | 8 | 0L | Long |
byte |
8 | 1 | 0 | Byte |
char |
16 | 2 | ‘u0000’ | Character |
float |
32 | 4 | 0f | Float |
double |
64 | 8 | 0d | Double |
boolean |
1 | false | Boolean |
这里需要注意的是 boolean在官方文档中并未明确定义,它依赖于JVM厂商的具体实现
基本数据类型直接存放在 Java 虚拟机栈中的局部变量表中,而包装类型属于对象类型,我们知道对象实例都存在于堆中。相比于对象类型, 基本数据类型占用的空间非常小。且包装类型不赋值就是NULL,而基本数据类型不赋值会有默认值但不是NULL。
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
例 :
Integer i = 10; //装箱
int n = i ; //拆箱
Integer i =10 这行代码就会发生装箱,具体就是 在编译时这行代码变成了 Integer i =Integer.valueof(10),也就是将10 这个 int 通过调用包装类Integer的valueof方法包装成了Integer。
int n=i 这行代码就会发生拆箱,在编译时变成了 int n = i.intValue(),通俗的讲也就是利用intValue方法将Integer变成了int
Byte
,Short
,Integer
,Long
这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character
创建了数值在 [0,127] 范围的缓存数据,Boolean
直接返回 True
or False
例:Integer i1=10
这一行代码会发生装箱,也就是说在编译的时候会将这行代码封装成 Integer i1=Integer.valueOf(10)
。因此,i1
直接使用的是常量池中的对象。而Integer i1 = new Integer(10)
会直接创建新的对象。
也就是说上述包装类按照Integer i1=10
方式创建的数值在一定范围内将不会创建新的对象,而是利用常量池中的对象,如果超出对应范围仍然会去创建新的对象,而如果是利用 new关键字进行创建的不管数值是否在该范围内都会创建新的对象。缓存的范围区间的大小只是在性能和资源之间的权衡。
两种浮点数类型的包装类 Float
,Double
并没有实现常量池技术。
封装是指将对象的一些属性隐藏在对象内部,让外界无法直接访问,但是可以通过某些公共方法间接访问私有属性。
继承,简单点来说就是通过一个已有的类,在该类(父类)的基础上创建一个新类(子类),子类拥有父类所有的属性、方法,包括私有属性、方法(但是不能访问),同时子类也可以进行扩展,创建自己的方法和属性。对于继承自父类的方法,子类可以选择重载和重写。
多态通俗一点理解就是 不同个体的相同行为可能产生不一样的效果
覆盖(重写)和重载
覆盖: 是对父类已有的方法的方法体进行覆盖重写, 返回值和形参都不能改变。即外壳不变,核心重写!
重载 :是在一个类里面,方法名相同,而参数不同,返回类型可以相同也可以不同。
String是不可变的、线程安全的,但性能是最低的(因为每次对String类型改变的时候,都会生成一个新的对象,然后将指针指向新的对象。)
首先 我们来了解一个关键字 final ,被final修饰的方法是不能被重写的,修饰的类是不能被继承的、修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。
在String类中,是利用了一个被final修饰的字符数组来存储字符串的,并且String类没有提供任何方法来对该数组进行修改。而String类也是被final修饰的,所以不存在子类去破坏String的不可变。
在 Java 9 之后,String 、
StringBuilder
与StringBuffer
的实现改用 byte 数组存储字符串private final byte[] value
StringBuffer是可变的,线程安全的、性能居中。继承至AbstractStringBuilder类,存储字符的结构未被final和private修饰,并且提供了可见的方法对字符串进行修改所以是可变的。在多线程下,由于StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
StringBuilder是可变的、线程不安全的、性能最好。继承至AbstractStringBuilder类,存储字符的结构未被final和private修饰,并且提供了可见的方法对字符串进行修改所以是可变的。但是在多线程环境下不安全。
对于三者使用的总结:
String
StringBuilder
StringBuffer
Object 类是一个特殊的类,是所有类的父类。它主要提供了以下 11 个方法:
public final native Class> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。
public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作
浅拷贝 :浅拷贝会根据原对象在堆上创建一个新的对象,但是对于该对象内部的引用类型的属性,浅拷贝只会直接复制内部对象的引用地址,并不会像对待原对象那样在堆上再建一个对象。也就是说拷贝对象和源对象的两个内部引用属性都是指向同一个对象的。
深拷贝 :深拷贝会完整的复制整个对象,包括这个对象的内部引用对象。
引用拷贝 :不会创建新的对象,只是复制对象的引用地址。
在运行时动态的获取类和类的属性的机制
参考地址
JAVA异常的结构如上图所示
Exception (异常):能被程序本身处理
受检查异常(必须处理):也就是说Java代码在编译过程中,如果受检查异常没有被处理的话,就没办法通过编译。
不受检查异常(可以不处理):Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。
Error
属于程序无法处理的错误,也就是我们没法通过catch进行捕获。常见的错误有:Java虚拟机运行错误、虚拟机内存不够、类定义错误等等。一般Java虚拟机会选择终止线程。
public String getMessage()
:返回异常发生时的简要描述public String toString()
:返回异常发生时的详细信息public String getLocalizedMessage()
:返回异常对象的本地化信息。使用 Throwable
的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()
返回的结果相同public void printStackTrace()
:在控制台上打印 Throwable
对象封装的异常信息try{}catch{}finally{}
try
**块: 用于捕获异常。其后可接零个或多个 catch
块,如果没有 catch
块,则必须跟一个 finally
块。catch
**块: 用于处理 try 捕获到的异常。finally
** 块:** 无论是否捕获或处理异常,finally
块里的语句都会被执行。当在 try
块或 catch
块中遇到 return
语句时,finally
语句块将在方法返回之前被执行在以下 3 种特殊情况下,finally
块不会被执行:
try
或 finally
块中用了 System.exit(int)
退出程序。但是,如果 System.exit(int)
在异常语句之后,finally
还是会被执行注意: 当 try 语句和 finally 语句中都有 return 语句时,在方法返回之前,finally 语句的内容将被执行,并且 finally 语句的返回值将会覆盖原始的返回值,也就是说最终的返回值会是finally中的返回值。
try-with-resources
适用范围(资源的定义): 任何实现 java.lang.AutoCloseable或者 java.io.Closeable 的对象
关闭资源和 finally 块的执行顺序: 在 try-with-resources 语句中,任何 catch 或 finally 块在声明的资源关闭后运行
使用方法 :
try(需要关闭的资源1;需要关闭的资源2....)
{
.....
}catch{...}
序列化 :在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。对于许多对象,像是使用大量引用的复杂对象,这种序列化重建的过程并不容易。面向对象中的对象序列化,并不概括之前原始对象所关系的函数。这种过程也称为对象编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组、deserialization、unmarshalling)
序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。
transient关键字的作用是: 阻止实例中被transient修饰的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。
transient只能修饰变量不能修饰类和方法。
transient修饰的变量,在反序列化后变量值将会被置成类型的默认值。
static关键字修饰的变量因为不属于任何对象,所以也不会被序列化。
方法1 Scanner
Scanner input = new Scanner([System.in](http://System.in));
String s = input.nextLine();
input.close();
方法2 BufferedReader
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();
UNIX系统下,I/O模型一共有5种:同步阻塞I/O、同步非阻塞I/O、I/O多路复用、信号驱动I/O和异步I/O。
BIO
阻塞型I/O,系统调用之后一直阻塞,直到数据被拷贝到用户区。
NIO
Java 中的 NIO 于 Java 1.4 中引入,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 对于高负载、高并发的(网络)应用,应使用 NIO
Java 中的 NIO 可以看作是 I/O 多路复用模型。也有很多人认为,Java 中的 NIO 属于同步非阻塞 IO 模型。
AIO
AIO也就是NIO2。属于异步IO型。
异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
本文参考☞本文参考网址