Bootstrap

JAVA小白学习日记Day11

反射

1. 反射
反射是指在运行时检查、获取和修改类的属性、方法、构造方法等信息的能力,可以在运行时动态地创建对象、调用方法、访问属性,而不需要在编译时确定。

2. 获取类对象的三种方式
在代码中展示了三种获取类对象(Class对象)的方法:

通过类名获取类对象:
Class clazz = EasyClassA.class;这种方式直接使用类名后跟 .class 来获取对应的 Class 对象。

通过对象获取类对象:
clazz = new EasyClassA().getClass();通过创建类的实例,然后调用 getClass() 方法来获取其对应的 Class 对象。

通过 Class.forName() 方法获取:
clazz = Class.forName("com.easy725.EasyColor");使用类的全限定名(包括包名)作为参数,调用 Class.forName() 方法来动态获取该类的 Class 对象。

3. Class 类对象的作用
Class 类对象包含了与类相关的信息,如属性、方法、构造方法等的定义。Class类的对象是不能new的。反射的核心是Class类,程序中使用的类,每一个都有一个唯一对应的Class对象。
在运行时,Java 使用 Class 对象来表示和管理类的结构和元数据,允许在运行时检查和操作类。

package com.easy726;

public class EasyClassA {
    //反射
    //有对象之前必须先有类,static来修饰类的属性和方法。
    //在java中存储了类的内容,这个内容也应该是一个对象。
    //java中每一个类都有一个内存,这每一块内存都是一个对象。
    //这些对象用来记录类中声明了哪些属性和方法以及构造方法。
    //java将这些类抽象为一个Class类。
    public static void main(String[] args) throws ClassNotFoundException {
        //Class类的对象是不能new的
        //获取类的类对象
        //1.通过类名获取类对象
        Class clazz=EasyClassA.class;
        //2.通过对象获取类对象
        clazz=new EasyClassA().getClass();
        //3.通过Class方法的forName方法获取
        clazz=Class.forName("com.easy725.EasyColor");
        System.out.println(clazz);
        //类的类对象中存储了类中定义的内容,属性/方法/构造方法。

    }
}

获取和设置属性值:Field
getField("name") 可以获取 Easy 类中名为 name 的公共属性,并且可以通过 fName.get(easy) 获取 easy 对象的 name 属性的值。
getDeclaredField("code") 可以获取 Easy 类中名为 code 的任意访问控制修饰符的属性(包括私有属性),但是在访问私有属性前需要调用 setAccessible(true) 设置访问权限。
注意事项:

getField 和 getFields 只能获取公共的字段(即使用 public 修饰的字段),而 getDeclaredField 和 getDeclaredFields 则可以获取类中声明的所有字段,不论其访问控制符是什么。对于私有字段,必须通过 setAccessible(true) 来解除访问限制。

package com.easy726;

import java.lang.reflect.Field;
import java.util.HashMap;

public class EasyClassB {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //类的类对象中存储了类中定义的内容(属性/方法/构造方法)。
        Class c=Easy.class;
        c=new Easy().getClass();
        c=Class.forName("com.easy726.Easy");
        //获取内容
        //1.获取类中的属性
        //java中用来记录类的属性的类叫做Filed。
        //fName指向的对象就是Easy类中的name属性。
        Field fName=c.getField("name");
        Easy easy=new Easy();
        easy.name="张三";
        System.out.println(easy.name);
        //可以获取某一个Easy类的对象的name属性的值
        Object objectName=fName.get(easy);
        System.out.println(objectName+"---");
        //注入该属性的值
        fName.set(easy,"李四");
        System.out.println(easy.name);
        //getField和getFields只能获取类中的public声明的属性
        Field fCode=c.getDeclaredField("code");
        fCode.set(easy,"10001");//设置code属性的值
        Object objCode=fCode.get(easy);//通过反射获取easy对象的code属性的值
        System.out.println(objCode);
        Field fSex=c.getDeclaredField("sex");
        Field fAddress=c.getDeclaredField("address");
        fSex.set(easy,"女");
        //反射访问私有属性,必须先获取访问权限。
        fAddress.setAccessible(true);
        fAddress.set(easy,"青岛");
        System.out.println(fAddress.get(easy));

        //getFields()

    }
}

getInstance 方法:

getInstance 方法利用反射创建一个指定类的对象,并根据传入的 values 参数设置对象的属性值。
Class.newInstance() 方法通过调用目标类的无参构造方法来实例化对象。
设置属性访问权限:
破坏类的封装性:

反射可以访问和修改类中私有的字段,这可能会破坏类的封装性,因为它允许绕过类的设计意图直接访问私有数据成员。

package com.easy726;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class EasyClassC {
    //反射:在程序运行期间,可以动态获取类中定义的属性和方法以及构造方法的机制(思想)的实现
    //反射的核心是Class类,程序中使用的类,每一个都有一个唯一对应的Class对象
    //反射的API:Field,Method,Constructor
    //反射会破坏类的封装性,通过场景说明
    public static <T> T getInstance(Class<T> tClass, Map values) throws IllegalAccessException, InstantiationException {
        //通过反射来获取实例,创建对象
        T t=tClass.newInstance();//通过类中的无参构造方法,创建对象。
        //通过反射获取类中定义的属性
        Field[] farr=tClass.getDeclaredFields();
        //System.out.println(Arrays.toString(farr));
        for (Field fitem:farr){
            //获取属性的名字
            String fname=fitem.getName();//获取属性的名字
            //获取该属性在Map中的键值对(属性对应的值)
            Object value=values.get(fname);
            //设置属性访问权限
            fitem.setAccessible(true);
            fitem.set(t,value);
        }
        return t;
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Map map=new HashMap<>();
        map.put("code","C10001");
        map.put("name","张三");
        map.put("esx","女");
        Student stu=getInstance(Student.class,map);
        System.out.println(stu);
    }
}
class Student{
    private String code;
    private String name;
    private String sex;

    @Override
    public String toString() {
        return "Student{" +
                "code='" + code + '\'' +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

获取方法对象:Method

Method ma = c.getMethod("methodA"); 使用 getMethod() 方法获取了 Easy 类中的名为"methodA" 的公共方法对象 ma。这里 "methodA" 是方法的名称,没有参数。
调用方法:

ma.invoke(easy); 通过 invoke() 方法调用了 easy 对象的 methodA() 方法。invoke() 方法允许在运行时动态地调用方法,即使不知道方法的具体名称和参数。
获取带参数的方法:

Method mb = c.getMethod("methodB", int.class, int.class); 使用 getMethod() 方法获取了 Easy 类中的名为 "methodB",且接受两个 int 类型参数的方法对象 mb。
调用带参数的方法:

mb.invoke(easy, 23, 45); 通过 invoke() 方法调用了 easy 对象的 methodB(int a, int b) 方法,传入了参数 23 和 45。这里的 mb 是 Method 对象,它可以动态调用 easy 对象的方法并传递参数。

package com.easy726;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class EasyClassD {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取类对象
        Class<Easy> c=Easy.class;
        //反射获取方法 Method
        Easy easy=c.newInstance();
        //获取public方法
        Method ma=c.getMethod("methodA");
        //调用方法
        //对象.方法名()   面向对象
        //method.invoke(对象)    反射的写法
        ma.invoke(easy);
        Method mb=c.getMethod("methodB", int.class, int.class);
        mb.invoke(easy,23,45);

    }
}

获取构造方法:Constructor

Class<Easy> c = Easy.class;Constructor<Easy> con = c.getConstructor(String.class);
通过 Class 对象获取类的构造方法,然后利用构造方法对象创建类的实例。

实例化对象:
con.newInstance("张三");使用获取到的构造方法对象调用 newInstance 方法来创建类的实例。

修饰符:使用Modifier的方法判断方法/属性/构造方法的修饰符。

获取属性的修饰符:
Field f = c.getDeclaredField("test");int fmod = f.getModifiers();
Boolean bool = Modifier.isStatic(fmod);
通过 Field 对象获取属性的修饰符,然后使用 Modifier.isStatic 方法判断属性是否为静态。
内省:
内省是一种通过反射来获取类的属性、方法等信息,但不会破坏类的封装性,主要用于获取和设置属性的读写方法。

获取属性的读写方法:
使用 Introspector.getBeanInfo 方法获取类的 BeanInfo,然后通过 PropertyDescriptor 获取属性的读写方法。

调用属性的setter方法:
Easy easy = c.newInstance();write.invoke(easy, "zhangsan");
使用反射调用 setter 方法设置属性的值。

package com.easy726;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.Arrays;

public class EasyClassE {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, IntrospectionException {
        //反射获取构造方法
        Class<Easy> c=Easy.class;
        c.newInstance();//调用无参构造方法
        Constructor<Easy> con=c.getConstructor();//获取无参构造方法
        con.newInstance();
        con=c.getConstructor(String.class);
        con.newInstance("张三");

        //修饰符,使用Modifier的方法判断方法/属性/构造方法的修饰符
        Field f=c.getDeclaredField("test");
        int fmod=f.getModifiers();
        Boolean bool=Modifier.isStatic(fmod);
        System.out.println(bool);

        //内省,也是通过反射来实现的,但是内省不会破坏封装性。
        //内省获取属性的读方法和写方法来获取和设置属性的内容,不会破坏类的封装性。
        //获取BeanInfo
        BeanInfo bi=Introspector.getBeanInfo(c);
        //获取属性的写的方法和读的方法(setter和getter)
        PropertyDescriptor[] pds=bi.getPropertyDescriptors();
        System.out.println(Arrays.toString(pds));
        String pName=pds[0].getName();//获取属性名字
        System.out.println("属性名是:"+pName);
        Method read=pds[0].getReadMethod();//对应属性的getter方法
        Method write=pds[0].getWriteMethod();//对应属性的setter方法
        //obj.setName("zhangsan");//面向对象
        //write.invoke(obj,"zhangsan");//反射
        Easy easy=c.newInstance();
        write.invoke(easy,"zhangsan");

    }
}

html常用标签   简单的css样式

文档类型声明
<!DOCTYPE html>定义了HTML文档类型,告诉浏览器这是一个HTML5文档。
HTML结构
<html>: HTML文档的根元素。
<head>: 包含了文档的元数据,如字符编码声明、标题和样式表。
<meta charset="utf-8">: 声明文档使用UTF-8字符编码,确保中文等非ASCII字符能正常显示。
<title>: 定义文档标题,显示在浏览器的标签页标题栏中。
<style>: 内部样式表,定义了表格和表格单元格的样式。
标题和段落
<h1>, <h2>: 定义标题,1级和2级标题。
<p>: 定义段落,包含文本内容。
图片和超链接
<img>: 插入图片,src属性指定图片路径,alt属性定义图片加载失败时的替代文本。
<a>: 创建超链接,href属性指定链接目标。
表格
<table>: 创建表格。
<tr>: 表格行。
<td>: 表格数据单元格。
colspan(合并列)和rowspan(合并行): 合并单元格。
列表
<ol>: 有序列表。
<ul>: 无序列表。
<li>: 列表项。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>页面标题</title>
		<style>
			table,td{
				border:1px solid deeppink;
				border-collapse: collapse;
			}
			td{
				width: 70px;
				text-align: center;
				padding: 10px;
			}
		</style>
	</head>
	<body>
		<!--标题  h1-h6 -->
		<h1>凉州词</h1>
		<h2>凉州词</h2>
		<!--段落-->
		<p>葡萄美酒夜光杯,欲饮琵琶马上催。</p>
		<!--图片-->
		<!-- .代表当前路径   ..代表上一级路径-->
		<img src="./image/easyimg.png" alt="加载失败" />
		<!-- 超链接-->
		<a href="https://www.baidu.com">链接到百度</a>
		<a href="easy.html">
			<img src="./image/easyimg.png" alt="加载失败" />
		</a>
		
		<table>
			<tr>
				<td>编号</td>
				<td>姓名</td>
				<td>成绩</td>
			</tr>
			<tr>
				<td>1001</td>
				<td>张三</td>
				<td>100</td>
			</tr>
		</table>
		<table>
			<tr>
				<td>1-1</td>
				<td colspan="2">1-2</td>
				<!-- <td>1-3</td> -->
				<td>1-4</td>
			</tr>
			<tr>
				<td rowspan="2">2-1</td>
				<td>2-2</td>
				<td>2-3</td>
				<td>2-4</td>
			</tr>
			<tr>
				<!-- <td>3-1</td> -->
				<td>3-2</td>
				<td rowspan="2" colspan="2">3-3</td>
				<!-- <td>3-4</td> -->
			</tr>
			<tr>
				<td>4-1</td>
				<td>4-2</td>
				<!-- <td>4-3</td>
				<td>4-4</td> -->
			</tr>
		</table>
		<!-- 列表 -->
		<!-- 有序列表(ol)和无序列表(ul)(有无序号) -->
		<ol>
			<li>苹果</li>
			<li>香蕉</li>
			<li>橘子</li>
		</ol>
		<ul>
			<li>苹果</li>
			<li>香蕉</li>
			<li>橘子</li>
		</ul>
	</body>
</html>

表单基础:

<form> 标签定义了一个表单,用于收集用户输入的数据,action 属性指定了表单提交的地址,method 属性指定了提交方式,可以是 get 或 post。
文本输入框:

<input type="text" name="username"/> 定义了一个文本输入框,用于用户输入用户名。
密码输入框:

<input type="password" name="userpassword"/> 定义了一个密码输入框,输入的内容会被隐藏显示。
隐藏域:

<input type="hidden" value="10001" name="id"/> 定义了一个隐藏域,用于存储不希望用户看到或修改的数据,如记录用户ID等。
只读文本框:

<input type="text" readonly value="202111050441" name="code"/> 定义了一个只读文本框,用户不能编辑其内容,仅用于显示。
单选框:

<input type="radio" value="Man" name="sex" id="sexman"/><label for="sexman">男</label> 定义了两个单选框,分别用于选择性别,通过 name 属性实现单选的互斥选择。
复选框:

<input type="checkbox" name="hobby" id="sing" value="sing"/><label for="sing">唱</label> 定义了多个复选框,用户可以选择一个或多个选项,通过 name 属性实现多选。
下拉框:

<select name="province" id="province"> 定义了一个下拉框,用户可以从预定义的选项中选择一个省份。
文本域:

<textarea name="description" id="description" cols="30" rows="10"></textarea> 定义了一个多行文本输入框,用户可以输入多行文本。
按钮:

<button type="submit">提交按钮</button> 是一个提交按钮,用户点击后会提交表单数据。
<button type="button">普通按钮</button> 是一个普通的按钮,不会触发表单提交。
<button type="reset">重置按钮</button> 是一个重置按钮,点击后会将表单中的内容重置为初始状态。
普通按钮(使用 input 标签):

<input type="button" value="普通按钮input"/> 也是一个普通的按钮,类似于上面的 <button> 元素,但使用了 <input> 标签。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<form action="提交表单的地址" method="提交方式get/post">
			<!-- 表单中的组件 -->
			<input type="text" name="username"/>
			<!-- 密码框 -->
			<input type="password" name="userpassword"/>
			<!-- 隐藏域 -->
			<input type="hidden" value="10001" name="id"/>
			<!-- 单选框 -->
			<!-- readonly只读 -->
			<input type="text" readonly value="202111050441" name="code"/>
			
			<!-- checked默认选中(互斥可覆盖) -->
			<div>
				<input checked type="radio" value="Man" name="sex" id="sexman"/><label for="sexman">男</label>
				<input type="radio" value="Woman" name="sex" id="sexwoman"/><label for="sexwoman">女</label>
			</div>
			<!-- 复选框 -->
			<!-- disable无法选中 -->
			<div>
				<input type="checkbox" name="hobby" id="sing" value="sing"/><label for="sing">唱</label>
				<input disabled type="checkbox" name="hobby" id="dance" value="dance"/><label for="dance">跳</label>
				<input type="checkbox" name="hobby" id="rap" value="rap"/><label for="rap">rap</label>
			</div>
			<!-- 下拉框 -->
			<!-- selected默认选中 -->
			<div>
				<label for="province">省份</label>
				<select name="province" id="province">
					<option value="sds">山东省</option>
					<option value="ahs">安徽省</option>
					<option value="xj" selected>新疆</option>
					<option value="sxs">陕西省</option>
					<option value="yns">云南省</option>
				</select>
			</div>
			<!-- 多行输入框(文本域) 两个标签中的内容就是他的值 注意不要回车-->
			<div>
				<textarea name="" id="" cols="30" rows="10"></textarea>
			</div>
			<button type="submit">提交按钮</button>
			<button type="button">普通按钮</button>
			<button type="reset">重置按钮</button>
			<input type="button" value="普通按钮input"/>
		</form>
	</body>
</html>

内部样式:
CSS样式定义了几种选择器:
#boxA: ID选择器,应用于id为boxA的元素,设置了宽度、高度、背景颜色、字体颜色等样式。
div: 标签选择器,应用于所有<div>元素,设置了宽度和高度。
.bgred: 类选择器,应用于所有类名为bgred的元素,设置了背景颜色为红色并隐藏(display: none;)。
内联样式和元素:
内联样式:直接在元素上使用style属性设置样式,例如第一个<div>的样式设置了宽度、高度和背景颜色。
ID选择器应用:第二个<div>使用了ID选择器#boxA,应用了预定义的样式。
类选择器应用:后面两个<div>使用了类选择器.bgred,共享类样式,设置了背景颜色为红色并隐藏。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			/* 内部样式 */
			/* 选择器 */
			/* ID选择器 */
			#boxA{
				width: 100px;
				height: 100px;
				background-color: black;
				/* 字体颜色 */
				color: aqua;
				/* 文本大小 */
				font-size: 20px;
				text-align: center;
				/* 单行文本垂直居中 行高等于容器的高度 */
				line-height:100px;
				/* 字体加粗 */
				font-weight: bold;
			}
			/* 标签选择器(元素选择器) */
			div{
				width: 100px;
				height: 100px;
			}
			/* 类选择器  class='bgred'*/
			.bgred{
				background-color: red;
				display: none;
			}
		</style>
	</head>
	<body>
		<!-- 内联样式 -->
		<div style="width: 100px;height: 100px;background-color:peru"></div>
		<div id="boxA">Hellow</div>
		<div class="bgred"></div>
		<div class="bgred"></div>
	</body>
</html>

;