23日目
2019年6月7日。
これは、私は、Javaを学ぶ23日目です。
この日、私は、次の知識を学びました。
コメント
注釈(アノテーション)、JDK5.0の最初から導入された新しい技術です。
次のように自然の注意事項は以下のとおりです。
- 注釈の役割
-注釈は、あなたが説明することができ、プログラム自体ではありません(これはコメント(コメント)違いはありませんです)プログラム
- (のような:コンパイラなど)、他のプログラムかもしれ読み出すために - 注釈付きフォーマット
-ノートは、「@注釈名が」コードに存在している、あなたはまた、のようないくつかのパラメータを追加することができます:@SuppressWarnings(値=「未チェック」 ) - 注釈の使用
-注釈は、これらのメタデータ・アクセス・プログラミング・反射によって達成することができ、それらに余分な補助情報を追加することと同等のものを与えるために、上記のパッケージ、クラス、メソッド、フィールドなどに取り付けることができます。
内蔵のノート次のように:
- @Override:このコメントに定義java.lang.Overrideは、別のメソッド宣言のスーパークラスをオーバーライドすることが意図されているメソッドの宣言を表し、修飾方法に適用されます
- @deprecated:java.lang.Deprecatedの定義は、この注釈は、それが危険であるか、より良い選択があるので、このような通常の要素は、プログラマを奨励表示されない、メソッド、プロパティ、クラスを変更するために使用することができます
- @SuppressWarnings:java.lang.SuppressWarnings警告コンパイル時を抑制するための定義。最初の2冊のノートには、あなただけの十分な使い分けを持つように、定義されているこれらのパラメータの適切な使用にパラメータを追加する必要があり、異なっています
例としては、次のとおりです:
public class Test {
//Override:重写方法的注解
@Override
public String toString() {
return "Test{}";
}
//Deprecated:不推荐使用,但是可以使用
@Deprecated
public static void stop(){
System.out.println("123");
}
//SuppressWarnings:抑制警告信息的注解
@SuppressWarnings("all")
public void test(){
}
public static void main(String[] args) {
stop();
}
}
人民元は、Javaは、他の注釈型のための命令を提供するために使用されている4つの標準のメタ注釈型を定義し、注釈が他の注釈を担当して、ノート、そして、彼らはパッケージをjava.lang.annotationできるクラスのこれらのタイプをサポート(見つけInheriter @、文書化の@リテンション@ @ターゲット、次のように)、その説明は以下のとおりです。
- @target:注釈の使用説明するために使用される(任意の場所で使用することができる記載即ち注釈、例えばElementType.METHOD方法に作用するが、ElementType.TYPEはクラスで使用されます)
- @Retention:どのようなレベルでの注釈情報を保存する必要性を表明し、それはノートのライフサイクルを記述するために使用される(SOURCE <CLASS <RUNTIME)
- @Document:説明このアノテーションはJavadocの中に含まれています
- @Inherited:説明サブクラスは、親クラスのノートを継承することができます
例としては、次のとおりです:
//测试元注解
@MyAnnotation
public class Test2 {
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) //作用域
@Retention(RetentionPolicy.RUNTIME) //运行时级别
@Documented //生成Doc文档时候使用
@Inherited //子类可以继承父类的注解
@interface MyAnnotation{
}
カスタム注釈は、自分たちのニーズ、注釈のうち、独自の定義に基づいています。自動的java.lang.annotation.Annotationインタフェースを継承するキーワード@interfaceカスタム注釈を使用してください。カスタムアノテーションを次のように:
- 注釈フォーマットを宣言するために使用@interface:公共@interface定義された注釈のコンテンツ名} {
- その方法のそれぞれは、実際には設定パラメータを宣言しています
- 名前は、メソッドのパラメータの名前です。
- 戻り値の型は、型パラメータである(戻り値は、基本的なタイプがあります。クラス、文字列、列挙型)
- あなたは、デフォルトでは、パラメータのデフォルト値を宣言することができます
- もしパラメータの唯一のメンバー、一般的なパラメータと呼ばれる値
- ノート要素我々は注釈要素を定義するとき、多くの場合、デフォルト値は0として空の文字列を使用して、値を持っている必要があります
例としては、次のとおりです:
//测试自定义注解
@SuppressWarnings("all")
public class Test3 {
@MyAnnotation2(name = "123",age = 3,id = 001,schools = "aa")
public void test(){
}
//注解只有一个参数的时候,默认使用value当做参数名字,使用的时候可以省略参数名
@MyAnnotation3("a")
public void test2(){
}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) //作用域
@Retention(RetentionPolicy.RUNTIME) //运行时级别
@interface MyAnnotation2{
//参数类型 参数名
String name() default "";
int age() default 0;
// -1 代表不存在,类似于Indexof的返回值
int id() default -1;
String[] schools() default {"a","b"};
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) //作用域
@Retention(RetentionPolicy.RUNTIME) //运行时级别
@interface MyAnnotation3{
String value();
}
反射
反射(反射)、キーは、動的Java言語であることがあり、プログラムは、アクチュエータリフレクションAPIによって反射は、任意のタイプの内部情報を取得することができ、任意のオブジェクトの内部プロパティとメソッドを直接操作することができます。
反射のための基本的な形式は:Class c = Class.forName("java.lang.String")
完成ローディングクラスの後、ヒープメモリ領域内のメソッドがクラスオブジェクトの種類(Classクラスのオブジェクトの一方のみ)を生成し、オブジェクトは、完全な構造情報のクラスが含ま。クラス構造は、オブジェクトを通して見ることができます。このオブジェクトは鏡のようで、ミラーは、この種の構造を通して見ることができます。反射:したがって、画像と呼ばれ
、以下のように反射を模式的に:
反射機構は、以下の機能を提供します。
- オブジェクトを分析することは、実行時に任意のクラスに属し、
- 任意の構成内のオブジェクトのランタイムクラスで
- 実行時に任意のクラスを決定することは、メンバ変数やメソッドを持っています
- 実行時に一般的な情報を取得します。
- 実行時にオブジェクトのいずれかのメンバ変数やメソッドを呼び出します
- 実行時に注釈を処理
- 動的プロキシを生成します
- ...
反射長所と短所次のように:
- 利点は、
大きな柔軟性を反映して、動的に作成されたオブジェクトを達成してコンパイルすることができます - 欠点は、
パフォーマンスに影響を与えます。反射は基本的に解釈操作で使用して、我々は我々がやりたい、それが私たちの要件を満たしている何をすべきか、JVMを伝えることができます。このような操作は、同じ操作が直接行われるよりも常に遅いです
例としては、次のとおりです:
//初始反射
//Class
public class Test {
public static void main(String[] args) {
try {
//通过反射获取类的class
Class c1 = Class.forName("Test2.User");
Class c2 = Class.forName("Test2.User");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
//正常创建对象的方式
User user = new User();
Class c3 = user.getClass();
System.out.println(c3.hashCode());
//总结:一个类无论创造多少个对象,只有一个Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//实体类
class User extends Object{
private String name;
private int id;
private int age;
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
密接クラスの反射とリンク:Classクラスは
Objectクラスの一つの方法で定義されています。public final Class getClass()
このメソッドは、すべてのサブクラスに継承されます。メソッドは、Javaリフレクションの源である値型クラスのクラスを返し、実際には、いわゆる業績は、ビューのプログラム点からの反射もまた十分に理解されています。すなわち:クラスの名前は、オブジェクトによって反射されるかを決定します。
情報オブジェクトミラーを得ることができる:クラス属性、メソッド、およびコンストラクタを、最終的にインターフェースを実装するクラスを。各クラスの用語については、JREはのための一定のClass型のオブジェクトを保持します。Classオブジェクトは、特定の構造に関する情報が含まれている次のように、クラスの特性は以下のとおりです。
- クラスは、クラス自体です
- Classオブジェクトは、ターゲット・システムによって確立することができます
- JVMにロードされたクラスは、クラスの唯一のインスタンスになります
- ClassオブジェクトにJVM 1つの.classファイルにロードされる対応
- クラスの各インスタンスは、クラスによって生成された覚えています
- クラスによって、あなたは完全にクラスのすべてのロードされた構造を得ることができます
- Classクラスは、対応するClassオブジェクトを取得するために、クラスを実行し、動的ロードしたい人のための反射の源であります
- Classクラスの一般的な方法は以下の通り:
-static ClassforName(String name)
:指定されたClassオブジェクトのクラス名の名前を返します
-Object newInstance()
:デフォルトのコンストラクタの呼び出しは、Classオブジェクトのインスタンスを返します
-getName()
:Classオブジェクトエンティティ(クラス、インタフェース、クラス、またはvoid配列を返します)名前
-Class getSuperClass()
:このクラスのオブジェクトの親クラスのクラスのオブジェクト
- :Class[] getinterfaces()
クラス・オブジェクト・インターフェースを取得
-ClassLoader getClassLoader()
:返すクラスローダクラス
-Constructor[] getConstructors()
:オブジェクトのコンストラクタを含む配列を返す
-Method getMother(String name,Class.. T)
:Methodオブジェクトを返し、パラメータタイプは、このオブジェクトは、paramTypeある
-Field[] getDeclaredFields()
フィールドオブジェクトの配列を返します。 - 以下の方法で、Classクラスのインスタンスを取得します:
-最も安全で信頼性の高い方法、およびプログラムの最高性能であるクラス属性クラスを通じて利用可能な特定のクラスを、既知の場合:Class clazz = Person.class;
-クラスの既知のインスタンスは、呼び出した場合:のgetClass()メソッドの例は、クラスオブジェクトを取得するClass clazz = person.getClass();
ClassNotFoundExceptionがスローできる)クラスの完全なクラス名を知られている場合、クラスパス内のクラスは、静的な方法でにforNameクラスクラスを(得ることができる: -Class clazz = Class.forName("demo1.Student")
-組み込みベースデータ型クラス名.TYPEとして使用することができる
-クラスローダによって
-注:クラスのインスタンスの取得アレイ場合、アレイ型の場合と同様に、唯一のクラスのオブジェクトと同じ大きさ、
-クラスのクラスの例については、次のように:
//测试如何获得class
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:" + person);
//1.通过对象获得class
Class c1 = person.getClass();
System.out.println(c1);
//2.通过forname :
Class c2 = Class.forName("Test2.Person");
System.out.println(c2);
//3,通过类的静态成员变量class 获得
Class c3 = Person.class;
System.out.println(c3);
//4.只有默认的基本类型才有的方法
//八大基本数据类型
//byte,int,short,long,double,float,char,boolean
Class type = Integer.TYPE;
//Integer.class
System.out.println(type);
//5.获得父类的类型
Class c4 = person.getClass();
Class c5 = c4.getSuperclass();
System.out.println(c4);
System.out.println(c5);
}
}
class Person{
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
あなたはClassオブジェクトを持っていたら、オブジェクトクラスを作成することができます。以下のようにのnewInstance()メソッド呼び出しを呼び出しているClassオブジェクトは、次のとおりです。
- このクラスは、引数なしのコンストラクタを持たなければなりません(明示的にコンストラクタクラスを呼び出して、口座にパラメータを渡すときの動作のみ、操作をインスタンス化することができます)
- クラスのコンストラクタへのアクセスは、十分な必要があり
要件を満たすために呼び出した後、以下の手順を呼び出します。
- このパラメータを取得するには、クラスのクラスgetDeclaredConstructor(クラス... parameterTypesパラメータ)の施工方法のクラスの型を指定します
- コンストラクタに必要な各種のパラメータを含む配列、にコンストラクタパラメータにオブジェクトを渡します
- オブジェクトのコンストラクタをインスタンス化することにより、
この呼び出しの後、反射によって、クラスのメソッド呼び出しは、メソッドのクラスを使用して完了することができます。次のステップ:
- メソッドのクラスクラスgetMethod(文字列名、クラス...たparameterTypes)メソッドを取得することにより、オブジェクト、およびこのタイプのパラメータを設定する操作方法が必要
- オブジェクト呼び出し使用した後(オブジェクトobjを、[オブジェクト ]引数) は以下のような方法で設定されるオブジェクトobjパラメータ情報を渡し、呼を、方法の性質がある:
(1).Objectは、元の戻り値に対応する元の方法であればNULL戻り値が返されていない
前者の方法は、静的メソッドである場合、パラメータオブジェクトobjがnullであってもよい。(2)
(3)。オリジナルのメソッドパラメータが空である場合、[]引数オブジェクトヌルである
(4)。元のメソッドの場合プライベートとして宣言され、(この呼び出しを呼び出す前に必要とされる)方法、表示方法setAccessible(真の)オブジェクトのメソッド呼び出し、民間へのアクセスは、
(5)。一般的に、通常は反射して、オブジェクトを作成し、<ランタイムオブジェクトを作成します時間を実行します(そうsetAccessibleが真である)<反射ランタイムオブジェクトによって作成された(注文setAccessibleはfalse)
次のように例を示します。
例としては、次のとおりです:
Userクラス:
//实体类
class User extends Object{
private String name;
private int id;
private int age;
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
の例
//获得类的信息
@SuppressWarnings("all")
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("Test2.User");
//获得名字
System.out.println(c1.getName()); //获得类的名字 : 包名 + 类名
System.out.println(c1.getSimpleName()); //获得类的名字简称
System.out.println("--------------------");
//获得属性
Field[] fields = c1.getFields(); //只能获得类的public属性
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = c1.getDeclaredFields(); // 获得类的所有属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("--------------------");
//获得方法
Method[] methods = c1.getMethods(); // 获得本类及其父类的所有public方法
for (Method method : methods) {
System.out.println("默认:" + method);
}
Method[] declaredMethods = c1.getDeclaredMethods();// 获得本类的所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println("Declared:" + declaredMethod);
}
System.out.println("--------------------");
//重载,如果只知道方法的名字,是找不到具体的方法
Method getName = c1.getDeclaredMethod("getName",null);
Method setName = c1.getDeclaredMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("--------------------");
//获取构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("--------------------");
//获得指定的构造器
Constructor constructor = c1.getConstructor(null); // 无参构造
System.out.println("默认:" + constructor);
constructor = c1.getConstructor(String.class,int.class,int.class);
System.out.println(constructor);
}
}
例二
//动态构造对象,调用方法
public class Test5 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c = Class.forName("Test3.User");
//1.通过动态调用构造方法,构造对象
User user = (User)c.newInstance();
System.out.println(user);
//2.通过有参构造创建对象
System.out.println("--------------------------------");
Constructor<User> declaredConstructor = (Constructor<User>) c.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = declaredConstructor.newInstance("a", 007, 18);
System.out.println(user2.getName());
//3.调用普通方法
System.out.println("--------------------------------");
User user3 = (User) c.newInstance();
//获得指定的方法
Method method = c.getDeclaredMethod("setName", String.class);
//invoke(方法执行的对象,方法参数的值)
method.invoke(user3,"a");
System.out.println(user3.getName());
//4.操作属性
User user4 = (User)c.newInstance();
Field field = c.getDeclaredField("name");
field.setAccessible(true); // 关闭权限访问检测,默认是false[打开权限访问检测]
//字段设置值(对象,值)
field.set(user4,"b");
System.out.println(user4.getName());
}
}
反射の他の特性
- setAccessible
-メソッド、およびフィールドは、コンストラクタオブジェクトは、setAccessible()メソッドがある
- setAccessibleアクションを有効および無効にされたスイッチングアクセスのセキュリティチェック
-真のパラメータ値は、オブジェクトは、Java言語アクセスチェックの使用に反映することを示します(これは、ようになりますキャンセルする必要がありますまた、アクセスすることができ、プライベートメンバにアクセスすることができない原稿は、反射コード必要な場合の反射の効率を向上させ、文章コード)がtrueに設定され、頻繁に呼び出される必要があること。
-性能試験の例は以下の通り:
//分析性能问题
public class Test6 {
//正常创建对象
public static void test1(){
User user = new User();
//获取时间
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("正常方式调用10亿次方法" + (endTime - startTime) + "毫秒");
}
//通过反射创建对象耗时
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method method = c.getMethod("getName",null);
//获取时间
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
method.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式调用10亿次方法" + (endTime - startTime) + "毫秒");
}
//通过反射创建对象耗时,关闭安全检测
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method method = c.getMethod("getName",null);
method.setAccessible(true); //提高性能
//获取时间
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
method.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭安全检测-->反射方式调用10亿次方法" + (endTime - startTime) + "毫秒");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test1();
test2();
test3();
}
}
- リフレクション操作のジェネリック
- Javaは、安全性を確保するために、のみを使用して、一般的な、Javaのジェネリックコンパイラのjavacを導入する一般的なメカニズムを使用して消去し、データキャストの問題を解消。しかし、一度コンパイル、すべてのタイプと関連するジェネリックすべて消去されます
-反射による操作、これらのタイプのために、Javaはクラスクラスに正規化することができない表現するためには、ParameterizedType、GenericArray、TypeVariableとWildcardTypeタイプを追加しましたしかし、データとオリジナル型PARの別のタイプは、これら4種類以下に記載されている:
(1).ParameterizedType:そのようなコレクションとして、パラメータ化された型を示す<ストリング>
(2).GenericArrayType:要素のタイプを表すパラメータであります変数の型のタイプまたは配列タイプは、
(3).TypeVariableは:インタフェースは共通の親変数型である
.WildcardType(4):ワイルドカード型の式を表し、
-以下のような例があります:
//测试反射获取泛型
@SuppressWarnings("all")
public class Test7 {
//带有泛型参数的方法
public void test(Map<String,User> map,List<User> list){
System.out.println("test01");
}
//带有泛型返回值的方法
public Map<Integer,User> test2(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//1.获得制定方法的泛型信息
Method method = Test7.class.getDeclaredMethod("test", Map.class, List.class);
//获得泛型参数类型信息
Type[] t = method.getGenericExceptionTypes();
for (Type type : t) {
System.out.println("#" + type);
if (type instanceof ParameterizedType){
//getActualTypeArguments 获得真实的类型参数
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实的泛型类型:" + actualTypeArgument);
}
}
}
//2.获得返回值泛型信息
Method method2 = Test7.class.getDeclaredMethod("test2",null);
//获得泛型返回的信息
Type genericReturnType = method2.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实的返回值类型:" + actualTypeArgument);
}
}
}
}
- 注釈反射動作
反射によって、注釈の情報を取得してもよいです。例としては、次のとおりです:
package Test3;
//使用反射读取注解
/*
1.定义注解
2.在类中使用注解
3.使用反射获取注解
*/
public class Test09 {
public static void main(String[] args) throws Exception {
//通过反射获取注解信息
Class c1 = Class.forName("Test3.Student2");
Annotation[] annotations = c1.getAnnotations();//获得这个类的所有注解信息
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的值
//通过注解的 value方法 获得注解的值
Annotation annotation = c1.getAnnotation(TableKuang.class);
TableKuang annotation1 = (TableKuang) annotation;
System.out.println(annotation1.value());
Field field = c1.getDeclaredField("id");
System.out.println(field);
//获得字段的注解
FieldKuang annotation2 = field.getAnnotation(FieldKuang.class);
//获得注解的参数信息
System.out.println(annotation2.columnName());
System.out.println(annotation2.length());
System.out.println(annotation2.type());
}
}
//学生的实体类
//db : database -->数据库
@TableKuang("db_student")
class Student2{
@FieldKuang(columnName = "id",type = "int",length = 10)
private int id;
@FieldKuang(columnName = "db_age",type = "int",length = 3)
private int age;
@FieldKuang(columnName = "name",type = "varchar",length = 20)
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//表名-->类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableKuang{
String value();
}
//字段类的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldKuang{
//参数类型 参数名
String columnName();//列名
String type();//类型
int length();//长度
}