入力ストリーム
InputStream |
Reader |
|
出力ストリーム
OutputStream | ライター |
|
![2502942685-57fdeddf4aac4_articlex](https://img.php.cn/upload/article/000/000/194/18241e05be71367d2b4a97ed82446b3b-0.png)
继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。
继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。
异常
![3190196716-57fdee43ad990_articlex](https://img.php.cn/upload/article/000/000/194/18241e05be71367d2b4a97ed82446b3b-1.jpg)
Java的异常(包括Exception和Error)分为:
可查的异常(checked exceptions)
除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
不可查的异常(unchecked exceptions)
包括运行时异常(RuntimeException与其子类)和错误(Error)。
运行时异常和非运行时异常:
RuntimeException
NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
RuntimeException以外的Exception
从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
注解
Java SE5内置了三种标准注解:
@Override,表示当前的方法定义将覆盖超类中的方法。
@Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
@SuppressWarnings,关闭不当编译器警告信息。
ログイン後にコピー
Java还提供了4中注解,专门负责新注解的创建:
@Target:
表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR
:构造器的声明
FIELD
:域声明(包括enum
实例)
LOCAL_VARIABLE
:局部变量声明
METHOD
:方法声明
PACKAGE
:包声明
PARAMETER
:参数声明
TYPE
:类、接口(包括注解类型)或enum
声明
@Retention
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE
:注解将被编译器丢弃
CLASS
:注解在class文件中可用,但会被VM丢弃
RUNTIME
:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息
@Document
将注解包含在Javadoc中
@Inherited
允许子类继承父类中的注解
Example
定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public String id();
public String description() default "no description";
}
ログイン後にコピー
使用注解:
public class PasswordUtils {
@UseCase(id = 47, description = "Passwords must contain at least one numeric")
public boolean validatePassword(String password) {
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id = 48)
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
}
ログイン後にコピー
解析注解:
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<Integer>();
Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, PasswordUtils.class);
}
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {
UseCase uc = m.getAnnotation(UseCase.class);
if (uc != null) {
System.out.println("Found Use Case:" + uc.id() + " "
+ uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for (int i : useCases) {
System.out.println("Warning: Missing use case-" + i);
}
}
// Found Use Case:47 Passwords must contain at least one numeric
// Found Use Case:48 no description
// Warning: Missing use case-49
// Warning: Missing use case-50
ログイン後にコピー
安全性
严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。
无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。
数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。
强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException
语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。
垃圾回收。
Exception。
类加载
原理
ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。
当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。
如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。
JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。
加载器
BootStrap ClassLoader
启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
// 也可以通过sun.boot.class.path获取
System.out.println(System.getProperty("sun.boot.class.path"))
ログイン後にコピー
Extension ClassLoader
扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
App ClassLoader
系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件
注意:
除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,
也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。
Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,
底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,
负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
ログイン後にコピー
关键字
strictfp(strict float point)
strictfp 关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。
如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。
transiant
变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。
Volatile
作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。
final
修饰基础数据成员(as const)
修饰类或对象的引用
修饰方法的final(cannot overwrite)
修饰类或者参数
初始化
父静态->子静态
父变量->父初始化区->父构造
子变量->子初始化区->子构造
多线程
java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
线程池
concurrent下的线程池:
名称 |
功能 |
ExecutorService |
真正的线程池接口 |
ScheduledExecutorService |
能和Timer/TimerTask类似,解决那些需要任务重复执行的问题 |
ThreadPoolExecutor |
ExecutorService的默认实现 |
ScheduledThreadPoolExecutor |
继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现 |
Executors
newSingleThreadExecutor
シングルスレッドのスレッドプールを作成します。このスレッド プールには 1 つのスレッドだけが動作しており、これはすべてのタスクを直列に実行する単一のスレッドと同等です。唯一のスレッドが異常終了した場合、新しいスレッドがそれを置き換えます。このスレッド プールにより、すべてのタスクが送信された順序で実行されることが保証されます。
newFixedThreadPool
固定サイズのスレッドプールを作成します。スレッドは、スレッド プールの最大サイズに達するまで、タスクが送信されるたびに作成されます。スレッド プールのサイズは、最大値に達しても変更されません。実行例外によってスレッドが終了すると、スレッド プールは新しいスレッドで補充されます。
newCachedThreadPool
キャッシュ可能なスレッド プールを作成します。スレッド プールのサイズがタスクの処理に必要なスレッドを超える場合、タスクの数が増加すると、一部のアイドル スレッド (60 秒間タスクが実行されない) がリサイクルされます。このスレッド プールは、タスクを処理するために新しいスレッドをインテリジェントに追加できます。このスレッド プールは、スレッド プールのサイズを制限しません。スレッド プールのサイズは、オペレーティング システム (または JVM) が作成できる最大スレッド サイズに完全に依存します。
newScheduledThreadPool
サイズ無制限のスレッド プールを作成します。このスレッド プールは、タスクのタイミングと定期的な実行をサポートします。
メモリ モデル
![180366427-57fdeea85b3e8_articlex](https://img.php.cn/upload/article/000/000/194/18241e05be71367d2b4a97ed82446b3b-2.png)
Java メモリ モデルは、複数のスレッドによって共有される変数がメイン メモリに格納されることを規定しています。スレッドは独自の作業メモリにのみアクセスできます。他のスレッドの。メイン メモリの共有変数のコピーは作業メモリに保存されます。これらの共有変数を操作するために、スレッドは作業メモリ内のコピーを操作することができます。操作が完了すると、そのコピーはメイン メモリに同期されます。
複数のスレッドが動作するときにメインメモリのデータの整合性をどのように確保するかは難しい問題です。Java メモリ モデルでは、まず、8 つのアトミック操作が定義されています。 : メインメモリ内の変数をロックし、1 つのスレッド専用にします
unlock: ロックを解除すると、他のスレッドがこの変数にアクセスできるようになります
read: 変数の値を読み取ります。メインメモリ 作業メモリに読み込みます
load: read で読み取った値を作業メモリ内の変数のコピーに保存します。
use: スレッドのコード実行エンジンに値を渡します。
assign: 実行エンジンから返された値を変数コピーに再割り当てします。
store: 変数コピーの値をメインメモリに保存します。
write: ストアに格納されている値をメインメモリのシェア変数に書き込みます。
メモリ構成
ヒープ
ランタイムデータ領域、すべてのクラスインスタンスと配列のメモリはここから割り当てられます。 Java 仮想マシンの起動時に作成されます。オブジェクトのヒープ メモリは、ガベージ コレクタと呼ばれる自動メモリ管理システムによって再利用されます。
ニュース世代(写真では若い世代はエデン+フロムスペース+トゥスペースです)
-
エデンには新しいオブジェクトが保存されます
-
非ヒープ メモリ
JVM には、アプリケーション内のすべてのスレッドで共有されるメソッド領域があります。メソッド領域は非ヒープメモリに属します。ランタイム定数プール、フィールド、メソッドのデータ、メソッドやコンストラクターのコードなど、すべてのクラス構造が保存されます。 Java 仮想マシンの起動時に作成されます。メソッド領域に加えて、Java 仮想マシンの実装には内部処理または最適化用のメモリが必要になる場合があります。これも非ヒープ メモリです。たとえば、JIT コンパイラは、高いパフォーマンスを実現するために、Java 仮想マシン コードから変換されたネイティブ コードを保存するためのメモリを必要とします。
永続生成 (図の永続スペース) は、クラス オブジェクトやメソッド オブジェクトなどの JVM 独自のリフレクション オブジェクトを保存します