Java 基础知识点 笔记总结 (十 一)

public void eat(){

System.out.println(“生物吃东西”);

}

}

MyAnnotation注解:

package exam.demo;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})

@Retention(RetentionPolicy.RUNTIME) //注解必须用RUNTIME的生命周期

public @interface MyAnnotation {

String value() default “hello”;

}

MyInterface接口:

package exam.demo;

public interface MyInterface {

void info();

}


整体上一个反射效果案例(了解,看后面):

package filefanxingTest;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import org.junit.Test;

public class ReflectionTest {

// 反射之前对于Person类的操作

@Test

public void test1() {

// 1.创建Person类的对象

Person p1 = new Person(“Tom”, 12);

// 2.通过对象,调用其内部的属性,方法

p1.age = 10;

System.out.println(p1.toString());

p1.show();

// 在Person外部,不可以通过Person类的对象调用其内部私有结构

// 比如,我们定义的name,showNation()方法以及私有的构造器。

}

// 反射之后,对于Person的操作

@Test

public void test2() throws Exception {

// 1.通过反射创建Person类的对象

Class clazz = Person.class;

Constructor cons = clazz.getConstructor(String.class, int.class);

Object obj = cons.newInstance(“Tom”, 12);

Person p = (Person) obj;

System.out.println(p.toString());

// 2.通过反射 ,调用对象指定的属性和方法

Field age = clazz.getDeclaredField(“age”);

age.set(p, 10);

System.out.println(p.toString());

Method show = clazz.getDeclaredMethod(“show”);

show.invoke§;

System.out.println(“*******************”);

// 通过反射,是可以调用Person类的私有结构的,比如:私有的构造器,私有的方法,私有的属性。

Constructor cons2 = clazz.getDeclaredConstructor(String.class);

cons2.setAccessible(true);

Person p2 = (Person) cons2.newInstance(“Jerry”);

System.out.println(p2);

// 调用私有属性

Field name = clazz.getDeclaredField(“name”);

name.setAccessible(true);

name.set(p2, “zhangsan”);

// 调用私有的方法

Method showNation = clazz.getDeclaredMethod(“showNation”, String.class);

showNation.setAccessible(true);

String nation = (String) showNation.invoke(p2, “中国”);// 相当于String nation = p1.showNation(“中国”);

System.out.println(nation);

}

}

反射可以给私有属性,私有方法,私有构造器来设置值。正常的new创建对象是不可以的!

3. 两个疑问(看自己理解)

============================================================================


通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底使用哪个呢?

建议:直接new的方式。

什么时候会使用:反射的方式? 反射的特征:动态性。


反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?

不矛盾,封装性提示的是你哪个方法能调用哪个方法不能调用(private),整体上算是一个限制提示建议的效果。

4. java.lang.Class 类的理解

=====================================================================================


类的加载过程:

程序经过javac.exe 以后,会生成一个或多个字节码文件(.class结尾)。

接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,这个过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。


**提示小结:

Idea项目下的out目录是用来存放.java文件编译后的字节码文件的。**


万事万物皆对象!

平常我们是对象.xxx属性 , File对象, URL对象等等。反射同样也是,就是通过Class的类对象,来实现的。

并且Class的实例就对应着一个运行时类,因此我们不能new一个Class,因为他是运行时类本身就存在的。

5. 如何获取Class实例的4中方式

=================================================================================


首先,第一点Class运行时类并不是我们自己创建出来的,而是它编译运行后自己有的类。

加载到内存中的运行时类,会缓存一定的时间。在此事件之内,我们可以通过4中不同的方式来获取此运行时类。(也就是只有一个运行时类,只不过获取方式不同。)

package com.test;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class ReflectionTest {

@Test

public void test3() throws ClassNotFoundException {

//方式一:调用运行时类的属性:.class

Class clazz1 = Person.class;

System.out.println(clazz1);

//也是可以加泛型的

//Class clazz1 = Person.class;

//方式二:通过运行时类的对象,调用getClass()来获取

Person p1 = new Person();

Class clazz2 = p1.getClass();

System.out.println(clazz2);

//方式三:调用Class的静态方法:forName(String classPath)

Class clazz3 = Class.forName(“com.test.Person”);

System.out.println(clazz3);

//我们比较一下他们的地址值,返回都是true,说明他们都是相同的运行时类,只不过获取的方式不同而已。

System.out.println(clazz1 == clazz2);//true

System.out.println(clazz1 == clazz3);//true

//方式四:使用类的加载器:ClassLoader

ClassLoader classLoader = ReflectionTest.class.getClassLoader();

Class clazz4 = classLoader.loadClass(“com.test.Person”);

System.out.println(clazz4);

System.out.println(clazz1 == clazz4);//true

}

}

6. Class实例可以是哪些结构?

================================================================================

package com.test;

import org.junit.jupiter.api.Test;

import java.lang.annotation.ElementType;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class ReflectionTest {

@Test

public void test4(){

Class c1 = Object.class;

Class c2 = Comparable.class;

Class c3 = String[].class;

Class c4 = int[][].class;

Class c5 = ElementType.class;

Class c6 = Override.class;

Class c7 = int.class;

Class c8 = void.class;

Class c9 = Class.class;

int[] a = new int[10];

int[] b = new int[100];

Class c10 = a.getClass();

Class c11 = b.getClass();

//只要元素类型与维度一样,就同一个Class

System.out.println(c10 == c11);//true

}

}

7. 类的加载 与 ClassLoader的理解

======================================================================================

7.1 类的加载过程



当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

在这里插入图片描述


这三个步骤必须牢记!

加载(Load):就是讲class文件字节码内容加载到内存中,转换为运行时数据结构,生成一个代码这个类的java.lang.Class对象。


链接(Link):正式为类变量(static类型)分配内存并设置类变量默认初始值,例如在static int a 在链接这个环节它就会被赋值默认初始值0,String b在链接就被默认赋值为null。


初始化:这个阶段有一个类构造器()方法,非常重要,它是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生。

当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。

在这里插入图片描述

7.2 类加载器(ClassLoader)的作用



类加载器的作用和类缓存:

在这里插入图片描述


类加载器作用就是用来把类(class)装载进内存的。

在这里插入图片描述

我们平时定义的类,都是通过系统类加载器来架子啊的,因此也算是最常用的加载器了。

package com.test;

import org.junit.jupiter.api.Test;

public class ClassLoadingTest {

@Test

public void test1(){

//对于定义类,使用系统类加载器进行加载

ClassLoader classLoader = ClassLoadingTest.class.getClassLoader();

System.out.println(classLoader);//这个就是AppClassLoader系统加载器

//调用系统类加载的getParent():获取扩展类加载器

ClassLoader classLoader1 = classLoader.getParent();

System.out.println(classLoader1);//这个就是ExtClassLoader拓展加载器

//调用扩展类加载器的getParent(): 无法直接获取引导类加载器的。

//引导类加载器主要负责加载java的核心类库,它是无法加载自定义类。

ClassLoader classLoader2 = classLoader1.getParent();

System.out.println(classLoader2);//这里返回null,并不是没有,而是引导类加载器不能直接获取。

//引导类加载器加载java的核心类库,例如String类型

ClassLoader classLoader3 = String.class.getClassLoader();

System.out.println(classLoader3);//这里也是返回null,说明String的加载器也是引导类加载器。

}

}

7.3 类加载器(ClassLoader) 加载配置文件Properties案例



我们在jdbc场景下,就有两种加载Properties文件的方式:

  • 读取配置文件方式一:使用FileInputStream方法,此路径默认是当前module工程模块下。

  • 读取配置文件方式二:使用ClassLoader , 此路径默认是当前module的src下。

package com.test;

import org.junit.jupiter.api.Test;

import java.io.FileInputStream;

import java.io.InputStream;

import java.util.Properties;

public class ClassLoadingTest {

/*

Properties:用来读取配置文件。

*/

@Test

public void test2() throws Exception {

Properties pros = new Properties();

//读取配置文件方式一:使用FileInputStream方法,此路径默认是当前module工程模块下。

FileInputStream fis = new FileInputStream(“jdbc.properties”);

//如果想用这种方式访问jdbc1.properties也是可以的,就是需要配置路径如下

//FileInputStream fis2 = new FileInputStream(“src\jdbc1.properties”);

pros.load(fis);

String user = pros.getProperty(“user”);

String password = pros.getProperty(“password”);

System.out.println(“姓名:”+user + “, 密码:” +password);

}

@Test

public void test3() throws Exception {

Properties pros = new Properties();

//读取配置文件方式二:使用ClassLoader , 此路径默认是当前module的src下。

ClassLoader classLoader = ClassLoadingTest.class.getClassLoader();

InputStream is = classLoader.getResourceAsStream(“jdbc1.properties”);

pros.load(is);

String user = pros.getProperty(“user”);

String password = pros.getProperty(“password”);

System.out.println(“姓名:”+user + “, 密码:” +password);

}

}

8. 反射 newInstance()方法 创建对应的运行时类的对象

================================================================================================


clazz.newInstance()方法:调用此方法,创建对应的运行时类的对象。该方法默认调用的就是类的空参构造器。

因此要想此方法能正常创建运行时类的对象,要求:

  • 1.运行时类必须提供空参的构造器。

  • 2.空参的构造器的访问权限得够!通常设置为public。


一个public的空参构造器,在javabean中很重要,原因如下:

  • 1.便于反射,创建运行时类的对象。

  • 2.便于子类继承此运行时类 时,默认调用super()时,保证父类有此构造器。


package com.Reflection;

import com.test.Person;

import org.junit.jupiter.api.Test;

public class NewInstanceTest {

@Test

public void test1() throws IllegalAccessException, InstantiationException {

Class clazz = Person.class;

/*

clazz.newInstance()方法:调用此方法,创建对应的运行时类的对象。

这里默认调用的就是类的空参构造器。

因此要想此方法能正常创建运行时类的对象,要求:

1.运行时类必须提供空参的构造器。

2.空参的构造器的访问权限得够!通常设置为public。

一个public的空参构造器,在javabean中很重要,原因如下:

1.便于反射,创建运行时类的对象。

2.便于子类继承此运行时类 时,默认调用super()时,保证父类有此构造器。

*/

Person p1 = (Person)clazz.newInstance();

System.out.println(p1);

}

}


通过newInstance()方法,来体现反射的一个动态效果:

package com.Reflection;

import com.test.Person;

import org.junit.jupiter.api.Test;

import java.util.Random;

public class NewInstanceTest {

/*

下面这种方式就体现了,反射的动态性效果。

*/

@Test

public void test2(){

//要一个随机值,nextInt(3)定义了以3为边界。

int num = new Random().nextInt(3);//0,1,2

String classPath = “”;

switch (num){

case 0:

classPath = “java.util.Date”;

break;

case 1:

classPath = “java.lang.String”;

break;

case 2:

classPath = “com.test.Person”;

break;

}

try {

Object obj = getInstance(classPath);

System.out.println(obj);

} catch (Exception e) {

e.printStackTrace();

}

}

/*

该方法创建一个指定类的对象。

classPath:指定类的全类名

*/

public Object getInstance(String classPath) throws Exception {

Class<?> clazz = Class.forName(classPath);

return clazz.newInstance();

}

}

9. 反射 获取运行时类的属性结构及其内部结构

=====================================================================================


获取属性结构

  • getFields():获取当前运行时类及其父类中声明为public访问权限的属性.

  • getDeclaredFields():获取当前运行时类中声明的所有属性,并且不包含父类中声明的属性。

package exam.demo2;

import exam.demo.Person;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

/*

获取当前运行时类的属性结构

*/

public class FieldTest {

@Test

public void test() throws Exception {

/*

Person是我自定义的一个类,

定义了int,String类型属性,创建一些方法,

设定注解,实现接口等等操作,这里就不添加person源码了,随便设定就可以。

*/

Class clazz = Person.class;

Class clazz2 = Class.forName(“exam.demo.Person”);

//获取属性结构

//getFields():获取当前运行时类及其父类中声明为public访问权限的属性

Field[] fields = clazz2.getFields();

for (Field f : fields){

System.out.println(f);

}

System.out.println(“*******************”);

//getDeclaredFields():获取当前运行时类中声明的所有属性,并且不包含父类中声明的属性。

Field[] declaredFields = clazz2.getDeclaredFields();

for (Field f : declaredFields){

System.out.println(f);

}

}

}


获取属性结构的权限修饰符,数据类型,变量名:

package exam.demo2;

import exam.demo.Person;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

/*

获取当前运行时类的属性结构

*/

public class FieldTest {

/*

属性的权限修饰符,数据类型,变量名的获取

*/

@Test

public void test2(){

Class clazz = Person.class;

Field[] declaredFields = clazz.getDeclaredFields();

for (Field f : declaredFields){

//1.f.getModifiers()获取当前属性的权限修饰符

int modifiers = f.getModifiers();

System.out.println(modifiers);//返回的是int类0,1,2,4

System.out.println(Modifier.toString(modifiers));

//2.f.getType()获取当前属性的数据类型

Class type = f.getType();

System.out.println(type + “,”);

System.out.println(type.getName());

//3.f.getName()获取当前属性的变量名

String name = f.getName();

System.out.println(name);

System.out.println(“--------------”);

}

}

}

get.getModifiers()返回值对应类型:

(default类型的值为: 0)

在这里插入图片描述


获取当前运行时类的属性结构的权限修饰符,注解,返回值类型,方法名和参数名 ,抛出异常。

注意如果反射需要接受注解啥的,那么注解的生命周期必须是runtime的!!

原因也很简单,反射是基于.class文件后的,因此注解也必须保留到那个时候。

package exam.demo2;

import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

/*

获取当前运行时类的属性结构的权限修饰符,返回值类型,方法名和参数名 ,抛出异常。

*/

public class FieldTest {

@Test

public void test() throws Exception {

Class clazz = Class.forName(“exam.demo.Person”);

Method[] declaredMethod = clazz.getDeclaredMethods();

for (Method m : declaredMethod){

//1. m.getAnnotations()方法:获取方法声明的注释

Annotation[] annotation = m.getAnnotations();

for (Annotation a : annotation){

System.out.println(a);

}

//2. m.getModifiers()方法:获取权限修饰符

System.out.print(Modifier.toString(m.getModifiers())+“\t”);

//3. m.getReturnType()方法:返回值类型

Class<?> returnType = m.getReturnType();

System.out.print(returnType+“\t”);

//4. m.getName()方法:方法名

String name = m.getName();

System.out.print(name+“\t”);

System.out.print(“(”);

//5. 形参列表

Class[] parameterTypes = m.getParameterTypes();

//没有参数类型的情况和有参数的情况区分

if (!(parameterTypes == null && parameterTypes.length == 0)){

for (Class c:parameterTypes){

//形参名

System.out.print(“参数名:”+c.getName());

}

}

System.out.print(“)”+“\t”);

//6. 获取抛出异常

Class<?>[] exceptionTypes = m.getExceptionTypes();

if (!(exceptionTypes == null && exceptionTypes.length == 0)){

for (Class c : exceptionTypes){

System.out.print(“异常:”+c.getName()+“\t”);

}

}

System.out.println();

}

}

}

10. 反射 获取运行时类的构造器结构

=================================================================================

获取构造器结构的方法:

package exam.demo2;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;

public class OtherTest {

/*

获取构造器结构

*/

@Test

public void test() throws ClassNotFoundException {

Class clazz = Class.forName(“exam.demo.Person”);

//clazz.getConstructors()方法:获取当前运行时类当中声明为public的构造器

Constructor[] constructors = clazz.getConstructors();

for (Constructor c : constructors){

System.out.print(c+“\t”);

System.out.println(c.getName());

}

System.out.println(“--------------”);

//clazz.getDeclaredConstructors()方法:获取当前运行时类中声明的所有构造器

Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

for (Constructor c : declaredConstructors){

System.out.print(c+“\t”);

System.out.println(c.getName());

}

}

}

11. 反射 获取父类或父类泛型结构

================================================================================

获取运行时类的父类及其父类泛型。

package exam.demo2;

import exam.demo.Person;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

public class OtherTest {

/*

获取运行时类的父类

*/

@Test

public void test2(){

Class clazz = Person.class;

//clazz.getSuperclass()方法:获取运行时的父类。

Class superclass = clazz.getSuperclass();

System.out.println(superclass);

System.out.println(superclass.getName());

}

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

{

System.out.print(c+“\t”);

System.out.println(c.getName());

}

System.out.println(“--------------”);

//clazz.getDeclaredConstructors()方法:获取当前运行时类中声明的所有构造器

Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

for (Constructor c : declaredConstructors){

System.out.print(c+“\t”);

System.out.println(c.getName());

}

}

}

11. 反射 获取父类或父类泛型结构

================================================================================

获取运行时类的父类及其父类泛型。

package exam.demo2;

import exam.demo.Person;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

public class OtherTest {

/*

获取运行时类的父类

*/

@Test

public void test2(){

Class clazz = Person.class;

//clazz.getSuperclass()方法:获取运行时的父类。

Class superclass = clazz.getSuperclass();

System.out.println(superclass);

System.out.println(superclass.getName());

}

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

[外链图片转存中…(img-11g2fpqZ-1714124424398)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值