Linux介紹及安裝配置
一 註解機制
1.1 內建註解
@Override:此註解只適用於修飾方法,表示一個方法宣告打算重寫父類中的另一個方法宣告
@Deprecated:此註解可以修飾方法、屬性、類,表示不鼓勵程式設計師使用這樣的元素,通常因為它很危險或存在更好的選擇
@SuppressWarning:用來鎮壓編譯時的警告資訊
- @SuppressWarning("all")
- @SuppressWarning("unchencked")
- @SuppressWarning(values={"unchecked", "deprecation"})
@SuppressWarnings("all") public void test02(){ // 定義了但沒有使用,預設是會出現警告的,但加了註解之後,警告消失(被鎮壓) LinkedList list = new LinkedList(); }
1.2 元註解
元註解的作用就是負責註解其它的註解,Java定義了4個標準的meta-annotation型別,它們被用來提供對其它的annotation型別作說明。
- @Target:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)
- @Retention:表示需要在什麼級別儲存該註解,用於描述註解的生命週期
- SOURCE < CLASS < RUNTIME(一般使用這個)
- @Document:說明該註解將被包含在javadoc中
- @Inherited:說明子類可以繼承父類中的註解
package zr.annotation; import java.lang.annotation.*; /** * 測試元註解 */ public class Test01 extends Object{ @MyAnnotation public void test(){ } } // 定義一個註解 @Inherited // Documented 表示是否將我們的註解生成在Javadoc中 @Documented // Recumented 表示註解的生命週期 @Retention(value = RetentionPolicy.RUNTIME) // Target 表示註解的使用範圍 @Target(value = {ElementType.METHOD, ElementType.TYPE}) @interface MyAnnotation{ }
1.3 自定義註解
使用@interface自動以註解時,自動繼承了java.lang.annotation.Annotation介面
- @interface用來宣告一個註解,格式:public @interface 註解名{定義內容}
- 其中的每一個方法實際上是聲明瞭一個配置引數
- 方法的名稱就是引數的名稱
- 返回值型別就是引數的型別(返回值只能是基本型別、Class、String、enum)
- 可以通過default來宣告引數的預設值
- 如果只有一個引數成員,一般引數名為value,在使用的時候可以把value省略掉
- 註解元素必須要有值,我們定義註解元素時,經常使用空字串、0作為預設值
二 反射機制
2.1 反射概念
Refelection(反射)是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API獲取任何類的內部資訊,並能直接操作任意物件的內部屬性及方法。
Class clazz = Class.forName("java.lang.String");
類載入完之後,在堆記憶體中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊,我們可以通過這個物件看到類的結構。這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以我們形象地稱之為:反射。
建立物件的方式:
- 正常方式:引入需要的“包類”名稱—>通過new關鍵字例項化—>取得例項化物件
- 反射方式:例項化物件—>getClass()方法—>得到完整的“包類”名稱
2.2 反射相關的API
- java.lang.Class:代表一個類
- java.lang.reflect.Method:代表類的方法
- java.lang.reflect.Field:代表類的成員變數
- java.lang.reflect.Constructor:代表類的構造器
- ......
2.3 獲取Class類的例項
-
若已知具體的類,通過類的class屬性獲取,該方法最為可靠,程式效能最高
Class clazz = Person.class;
-
已知某個類的例項,呼叫該例項的getClass()方法獲取Class物件
Class clazz = person.getClass();
-
已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取
Class clazz = Class.forName("zr.reflection.User");
-
內建基本資料型別可以直接用類名.Type(比如Integer.Type返回的就是int)
-
利用ClassLoader
package zr.reflection;
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("這個人是: " + person.name);
// 方式一:通過物件獲得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
// 方式二:forName獲得
Class c2 = Class.forName("zr.reflection.Student");
System.out.println(c2.hashCode());
// 方式三:通過類名.class獲得
Class c3 = Student.class;
System.out.println(c3.hashCode());
// 獲取父類型別
Class c4 = c1.getSuperclass();
System.out.println(c4);
}
}
class Person{
public String name;
public Person(){}
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student(){
this.name = "學生";
}
}
package zr.reflection;
import java.lang.annotation.ElementType;
// 所有的型別的Class物件
public class Test02 {
public static void main(String[] args) {
// 類
Class c1 = Object.class;
// 介面
Class c2 = Comparable.class;
// 一維陣列
Class c3 = String[].class;
// 二維陣列
Class c4 = int[][].class;
// 註解
Class c5 = Override.class;
// 列舉
Class c6 = ElementType.class;
// 基本資料型別
Class c7 = Integer.class;
// void
Class c8 = void.class;
// Class本身
Class c9 = Class.class;
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
// 只要元素型別與維度一致,就是同一個Class物件
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
// 輸出結果:
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
356573597
356573597
2.4 什麼時候會發生類初始化
類的載入過程:載入—>連結—>初始化
2.4.1 類的主動引用
- 當虛擬機器啟動,先初始化main方法中的所有宣告的類
- new一個類的物件
- 呼叫類的靜態成員(除了final static靜態常量)和靜態方法
- 使用java.lang.reflection包的方法對類進行反射呼叫
- 當初始化一個類,如果其父類沒有被初始化,則先會初始化它的父類
2.4.2 類的被動呼叫(不會發生類的初始化)
- 當訪問一個靜態域,只有真正宣告這個域的類才會被初始化。如:子類引用父類的靜態變數,不會導致子類的初始化
- 通過陣列定義類引用
- 引用常量(因為常量在連結階段就已經存入呼叫類的常量池中了)
2.5 類載入器
類載入器的作用:將class位元組碼檔案內容載入到記憶體中,並將這些靜態資料轉換成方法區的執行時資料結構,然後在堆中生成一個代表這個類的一個java.lang.Class物件,作為方法去中類資料的訪問入口。
雙親委派模型:從下到上檢測類是否被載入,從上到下嘗試載入類
package zr.reflection;
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
// 獲取系統類的載入器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 獲取系統類載入器的父類載入器——>擴充套件類載入器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
// 獲取擴充套件類載入器的父類——>根載入器(C/C++寫的,所以一般獲得null)
ClassLoader boot = parent.getParent();
System.out.println(boot);
// 測試自定義類是由誰載入的(由系統類載入器載入)
ClassLoader loader = Class.forName("zr.reflection.Test01").getClassLoader();
System.out.println(loader);
// 測試JDK內部類是由誰載入的(由boot根載入器載入)
loader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(loader);
// 檢視系統類載入器可以載入的路徑
System.out.println(System.getProperty("java.class.path"));
/*
D:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;
D:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;
E:\idea\out\production\idea;
E:\idea\lib\mysql-connector-java-8.0.21.jar;
D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.2.2\lib\idea_rt.jar
*/
}
}
// 輸出結果
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1540e19d
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
2.6 獲得類的執行時結構
package zr.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
// 獲得類的資訊
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException {
Class clazz = Class.forName("zr.reflection.Student");
// 獲得類的名字
System.out.println(clazz.getName()); // 獲得包名 + 類名
System.out.println(clazz.getSimpleName()); // 獲得類名
// 獲得類的屬性
Field[] fields = clazz.getFields(); // 只能找到public屬性
fields = clazz.getDeclaredFields(); // 能獲得所有宣告的屬性
for(Field field : fields)
System.out.println(field);
// 獲得類的方法
Method[] methods = clazz.getDeclaredMethods(); // 獲取本類的所有方法(私有的也行)
for(Method method : methods)
System.out.println();
// 獲得類的構造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor constructor : constructors)
System.out.println(constructor);
}
}
2.7 獲得Class物件後的操作
package zr.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// 獲得類的資訊
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 獲得Class物件
Class clazz = Class.forName("zr.reflection.User");
// 構造一個物件
User user = (User)clazz.newInstance(); // 本質上是呼叫了類的無參構造器
System.out.println(user);
// 通過構造器建立物件,這樣就可以間接地去使用User的有參構造器
Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class, int.class);
User xiaozeng = (User)constructor.newInstance("曾潤", 24, 99);
System.out.println(xiaozeng);
// 通過反射呼叫普通方法
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(xiaozeng, "範春春");
System.out.println(xiaozeng);
// 通過反射操作屬性
Field name = clazz.getDeclaredField("name");
// 首先需要設定許可權,防止private修飾的變數不能修改
name.setAccessible(true);
name.set(xiaozeng, "曾益達"); // 相當於賦值語句: name = "曾益達";
System.out.println(xiaozeng);
}
}
// 輸出
User{name='null', age=0, grade=0}
User{name='曾潤', age=24, grade=99}
User{name='範春春', age=24, grade=99}
User{name='曾益達', age=24, grade=99}
2.8 通過反射操作泛型
package zr.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class Test05 {
public static void test01(Map<String, User> map, List<User> list){
System.out.println("test01");
}
public static Map<String, User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Class clazz = Test05.class;
Method method = clazz.getDeclaredMethod("test01", Map.class, List.class);
// 獲得泛型的引數資訊
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
System.out.println("# " + genericParameterType);
Type[] actualyTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for(Type actualyTypeArgument : actualyTypeArguments)
System.out.println(actualyTypeArgument);
}
}
}
// 輸出結果
# java.util.Map<java.lang.String, zr.reflection.User>
class java.lang.String
class zr.reflection.User
# java.util.List<zr.reflection.User>
class zr.reflection.User
2.9 通過反射操作註解
package zr.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test06{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class clazz = Class.forName("zr.reflection.Student1");
// 通過反射獲取類的註解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 獲得註解的value值
Tablerun tablerun = (Tablerun) clazz.getAnnotation(Tablerun.class);
String value = tablerun.value();
System.out.println(value);
// 獲得類指定的註解
Field name = clazz.getDeclaredField("name");
Fieldrun annotation = name.getAnnotation(Fieldrun.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Tablerun("db_student")
class Student1{
@Fieldrun(columnName = "db_id", type = "int", length = 10)
private int id;
@Fieldrun(columnName = "db_age", type = "int", length = 10)
private int age;
@Fieldrun(columnName = "db_name", type = "varchar", length = 3)
private String name;
public Student1(){}
public Student1(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 "Student1{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
// 類名的註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablerun{
String value();
}
// 屬性的註解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldrun{
String columnName();
String type();
int length();
}
// 輸出結果
@zr.reflection.Tablerun(value=db_student)
db_student
db_name
varchar
3