12.23实验 请问实验
lipiwang 2024-10-23 14:02 9 浏览 0 评论
1. 编写一个方法,通过反射机制获取一个对象的所有成员变量(包括私有变量),并将其值打印出来。
首先是利用反射获取成员变量
对比上篇的构造方法,大家有没有发现前面几乎只是变量和方法的区别,其他几乎一样?
话不多说,直接代码演示
首先,依旧是创建一个Student类,封装其javabean
package com.ittaotao.myreflect3;
public class Student {
private String name;
private int age;
public String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
返回成员变量
package com.ittaotao.myreflect3;
import java.lang.reflect.Field;
public class MyReflectDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//1.首先,咱们依旧是要获取字节码文件的对象
Class clazz = Class.forName("com.ittaotao.myreflect3.Student");
//2.获取里面的成员变量对象(公共的成员变量对象)
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------------");
//2.获取里面的成员变量对象(包括私有的成员变量对象)
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
System.out.println("---------------------");
//3.获取单个的成员变量
Field gender = clazz.getField("gender");
System.out.println(gender);
System.out.println("---------------------");
//4.获取私有的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
}
}
运行结果
获取权限修饰符、名字、数据类型、成员变量记录的值,同时我们也可以修改对象里面的值
//5.获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
System.out.println("---------------------");
//6.获取成员变量名字
String n = name.getName();
System.out.println(n);
System.out.println("---------------------");
//7.获取数据类型
Class type = name.getType();
System.out.println(type);
System.out.println("---------------------");
//获取成员变量记录的值
//因为其与对象有关,所以,想要获取值,首先要先创建一个对象
Student s = new Student("zhangsan",23,"男");
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);
System.out.println("---------------------");
//修改对象里面的值--把s对象里面的name修改成lisi
name.set(s,"lisi");
System.out.println(s);
以上就是利用反射获取成员变量的一些方法了
最后,我们来说一下利用反射获取成员方法
我们可以发现获取方法的规律都是一样的
废话不多说,直接代码演示
首先一样,我们先创建student类,不过这次我们加了sleep和eat方法
package com.ittaotao.myreflect4;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void sleep(){
System.out.println("睡觉");
}
public void eat(String something){
System.out.println("在吃" + something);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
首先,获取里面所有的方法对象(包含父类中所有的公共方法)
package com.ittaotao.myreflect4;
import java.lang.reflect.Method;
ublic class MyReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
//1.获取class字节码文件对象
Class clazz = Class.forName("com.ittaotao.myreflect4.Student");
//2.获取里面所有的方法对象
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
//获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
Method[]methods1 = clazz.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method);
}
返回单个成员方法对象
//因为eat方法是私有的,所以我们要用getDeclaredMethod方法进行调用
Method m = clazz.getDeclaredMethod("eat",String.class);
System.out.println(m);
获取方法的修饰符
//获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);
获取方法的名字
//获取方法的名字
String name = m.getName();
System.out.println(name);
获取方法的形参
//获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
获取方法的抛出的异常
//获取方法抛出的异常 这里我们需要在student代码中加入异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
获取方法并运行
//方法运行
/*
* Method类中用于创建对象的方法
* Object invoke(Object obj,Object...agrs):运行方法
* 参数一:用obj对象调用方法
* 参数二:调用方法的传递的参数(如果没有就不写)
* 返回值:方法的返回值(如果没有就不写)
* */
Student s = new Student();
m.setAccessible(true);
//参数一s:表示方法的调用者
//参数二“汉堡包”:表示在调用方法的时候传递的实际参数
m.invoke(s,"汉堡包");
倘若有返回值,student类需要进行修改
public String eat(String something) throws IOException,NullPointerException,ClassCastException {
System.out.println("在吃" + something);
return "奥利给";
}
Student s = new Student();
m.setAccessible(true);
//参数一s:表示方法的调用者
//参数二“汉堡包”:表示在调用方法的时候传递的实际参数
Object result = m.invoke(s, "汉堡包");
System.out.println(result);
2. 编写一个方法,通过反射机制获取一个类的所有方法(包括继承的方法),并将其名称和参数列表打印出来。
一、什么是反射?
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码文件对象的三种方式。
1、Class clazz1 = Class.forName("全限定类名"); //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
2、Class clazz2 = Person.class; //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3、Class clazz3 = p.getClass(); //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。下面介绍Class类的功能。
二、反射机制能够获取哪些信息?Class类的API详解。
2.1、通过字节码对象创建实例对象
2.2、获取指定构造器方法。constructor 如果没有无参构造,只有有参构造如何创建实例呢?看下面
总结上面创建实例对象:Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的 getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象
获取全部构造方法
2.3、获取成员变量并使用 Field对象
获取指定成员变量
Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
获取全部成员变量
2.4、获得方法并使用 Method
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,
如果为私有方法,则需要打开一个权限。setAccessible(true);
用invoke(Object, Object...)可以调用该方法,
跟上面同理,也能一次性获得所有的方法
2.5、获得该类的所有接口
Class[] getInterfaces():确定此对象所表示的类或接口实现的接口
返回值:接口的字节码文件对象的数组
2.6、获取指定资源的输入流
InputStream getResourceAsStream(String name)
return:一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null
参数:所需资源的名称,如果以"/"开始,则绝对资源名为"/"后面的一部分。
2.7、动态代理的概述和实现
动态代理:一种设计模式,其非常简单,很容易理解,你自己可以做这件事,但是觉得自己做非常麻烦或者不方便,所以就叫一个另一个人(代理)来帮你做这个事情,而你就不用管了,这就是动态代理。举个例子,买火车票叫人代买。
在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
分三步,但是注意JDK提供的代理正能针对接口做代理,也就是下面的第二步返回的必须要是一个接口。
1、new出代理对象,通过实现InvacationHandler接口,然后new出代理对象来。
2、通过Proxy类中的静态方法newProxyInstance,来将代理对象假装成那个被代理的对象,也就是如果叫人帮我们代买火车票一样,那个代理就假装成我们自己本人
3、执行方法,代理成功
将代理对象中的内容进行实现
注意newProxyInstance的三个参数,第一个,类加载器,第二个被代理对象的接口,第三个代理对象。
2.8、还有很多方法,比如获得类加载器,等等
具体还需要别的,就通过查看API文档来解决。
三、反射机制的应用实例
3.1、利用反射,在泛型为int的arryaList集合中存放一个String类型的对象
原理:集合中的泛型只在编译器有效,而到了运行期,泛型则会失效,
3.2、利用反射,简化编写Servlet的个数。
什么意思呢?每当我们写一个功能时,就需要写一个对应的Servlet,导致最后Servlet有很多,自己都看不过来,所以对其进行了优化,两种方式,
3.2.1、每次从页面传过来一个参数,method="xxx"; 然后编写一个Servlet,获得其参数method的值,进行判断,如果是add,则调用add方法,如果是delete,则调用delete方法,这样就可以写在一个servlet中实现所有的功能了。
3.2.2、利用反射
编写一个BaseServlet继承HttpServlet,这是一个通用的BaseServlet。需要明白servlet的生命周期
编写具体实现的方法servlet类。
MySerlvet001 extends BaseServlet
解释:需要明白servlet的生命周期,也就是service方法,因为是servlet,所以在访问的时候,会经过service方法,而子类MyServlet001中并没有,所以就到父类BaseServlet中找,发现有,然后获取参数即知道了需要调用什么方法,因为方法的编写都在子类中,所以通过反射,获取到子类中对应的方法并运行,其中需要注意的是this这个参数在BaseServlet中的用法。需要理解它。才能理解我们这个程序。
四、总结
反射基本上就这样讲完了,其实就是对其一些api进行讲解,不懂的就查看API,重要的思想,就要在实际中遇到了才能得到更好的理解。先这样过一遍,零零碎碎的知识。
3. 编写一个方法,通过反射机制动态创建一个对象,并根据用户的输入动态设置对象的属性值。
前言:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
这里的反理解为反转,控制反转。假如我们需要零花钱就找老婆要,这是“正”。但是现在反过来是老婆主动给我们,这是“反”。虽然最后的结果都一样,都是老婆给我们零花钱,但是方式不一样。程序中以前创建对象是通过new来创建对象,自上而下。但是现在我们可以使用反射技术反过来自下而上的提供访问。反射相关的类都在java.lang.reflect包下。
代码部分:
computer类:
package com.dmdd.ioc;
public class Computer {
private String brand;
private Cpu cpu;
private Memory memory;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Cpu getCpu() {
return cpu;
}
public void setCpu(Cpu cpu) {
this.cpu = cpu;
}
public Memory getMemory() {
return memory;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
public void start (){
System.out.println(brand+"品牌的电脑启动了");
cpu.run();
memory.read();
memory.write();
}
}
1.类名.class创建反射对象:
public static void main(String[] args) {
Class<Computer> computerClass = Computer.class;
}
2.对象.getclass创建反射对象:
public static void main(String[] args) {
Computer computer = new Computer();
Class<? extends Computer> aClass = computer.getClass();
}
3.Class.forName("")创建反射对象:
public static void main(String[] args) {
try {
Class.forName("com.dmdd.ioc.Computer");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
4. 编写一个方法,实现简单的IOC(控制反转)功能,通过反射机制自动注入依赖的对象。
Reflect类声明如下:
typedef QWidget* (*Constructor)(QWidget* parent);
Reflect实现如下
Reflect::Reflect()
测试用例类注册:
Form类声明:
```cpp
#include <QLabel>
#include "reflect.h"
class Form : public QLabel
{
Q_OBJECT
public:
explicit Form(QWidget *parent = nullptr);
~Form();
};
DECLARE_WIDGET_REFLECT(Form)
Form实现:
#include "form.h"
Form::Form(QWidget *parent) :
QLabel(parent)
{
setText("通过类名动态创建的画面");
setAlignment(Qt::AlignCenter);
}
Form::~Form()
{
}
IMPL_WIDGET_REFLECT(Form)
测试用例使用
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "reflect.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//通过类名信息动态创建已注册类的对象
setCentralWidget(Reflect::reflect(this,"Form"));
}
MainWindow::~MainWindow()
{
delete ui;
}
注意:这种方式会给每个需要动态创建的类专门定义一个辅助类。
5. 编写一个方法,通过反射机制动态代理一个接口的实现类,实现在调用接口方法前后加入一些额外的逻辑。
一、JDK动态代理
核心接口和类:InvocationHandler(调用处理器接口) 和 Proxy(代理类) 。
定义:
public interface InvocationHandler
public class Proxy implements java.io.Serializable
Proxy API:
static InvocationHandler getInvocationHandler(Object proxy)
返回指定代理实例的调用处理器。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
返回给定类加载器和接口数组的代理类的 java.lang.Class 对象。
static boolean isProxyClass(Class<?> cl)
当且仅当使用 getProxyClass 方法或 newProxyInstance 方法将指定的类动态生成为代理类时,才返回 true。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派到指定的调用处理器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1、调用处理器
调用处理器是实现了 InvocationHandler 接口的类对象。InvocationHandler 接口只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
1
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用,并向其传递 Method 对象和原始的调用参数。
调用处理器必须给出处理调用的方式。
2、代理类:Proxy
2.1 创建一个代理对象,需要使用 Proxy 类的 newProxyInstance 方法。 该方法有三个参数:
一个类加载器(class loader) 。使用 null 表示使用默认的类加载器。
一个 Class 对象数组,每个元素都是需要实现的接口。
一个调用处理器。
2.2 代理类能够实现指定的接口。尤其是,它具有下列方法:
指定接口所需要的全部方法。
Object 类中的全部方法,例如,toString、equals 等。
代理类是在程序运行过程中创建的。然而,一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。
2.3 没有定义代理类的名字,虚拟机中的 Proxy 类将生成一个以字符串 $Proxy 开头的类名。
2.4 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次 newProxyInstance 方法的话,那么只能够得到同一个类的两个对象,也可以利用 getProxyClass 方法获得这个类:
Class proxyClass = Proxy.getProxyClass(null, interfaces);
1
2.5 代理类一定是 public 和 final。如果代理类实现的所有接口都是 public,代理类就不属于某个特定的包;否则,所有非公有的接口都必须属于同一个包,同时,代理类也属于这个包。可以通过调用 Proxy 类中的 isProxyClass 方法检测一个特定的 Class 对象是否代表一个代理类。
二、JDK动态代理 与 CGLIB动态代理
1、区别
1.1 原理区别
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvocationHandler 来处理。
CGLIB动态代理是利用cglib开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1.2 JDK动态代理和CGLIB字节码生成的区别
JDK动态代理只能对实现了接口的类生成代理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成 final 。
1.3 Spring AOP 动态代理
如果目标对象实现了接口,默认情况下采用JDK的动态代理来实现 AOP 。但是也可以强制使用 CGLIB 来实现 AOP 。
如果目标对象没有实现了接口,只能采用 CGLIB,Spring会自动在JDK动态代理和CGLIB之间切换。
2、代码示例
UserService接口
package site.itool;
/**
* UserService接口
*/
public interface UserService {
// 通过用户id打印用户姓名
void printUserName(Long id);
}
1
2
3
4
5
6
7
8
9
UserService接口实现类
package site.itool;
/**
* UserService接口实现类
*/
public class UserServiceImpl implements UserService {
/**
* 实现接口方法
* @param id
*/
@Override
public void printUserName(Long id) {
System.out.println("(代理对象)姓名是" + id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JDK动态代理
package site.itool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK代理类 调用处理器
*/
public class JdkProxy implements InvocationHandler {
private Object target ; // 需要代理的目标对象
public JdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理,开始!");
Object result = method.invoke(target, args);
System.out.println("JDK动态代理,结束!");
return result;
}
/**
* 获取代理对象方法
* @return
*/
private Object getJDKProxy(){
// JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(new UserServiceImpl());
// 获取代理对象
UserService user = (UserService)jdkProxy.getJDKProxy();
user.printUserName(1L); //执行方法
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
输出:
CGLIB动态代理
package site.itool;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB代理类 调用处理器
*/
public class CglibProxy implements MethodInterceptor {
private Object target ; // 需要代理的目标对象
public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB动态代理,开始!");
Object invoke = method.invoke(target, objects); // 方法执行,参数:target 目标对象 objects 参数数组
System.out.println("CGLIB动态代理,结束!");
return invoke;
}
/**
* 获取代理对象方法
* @return
*/
public Object getCglibProxy(){
Enhancer enhancer = new Enhancer();
// 设置父类,因为 CGLIB 是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this); // 设置回调
Object result = enhancer.create(); // 创建并返回代理对象
return result;
}
public static void main(String[] args) {
CglibProxy cglib = new CglibProxy(new UserServiceImpl());
// 获取代理对象
UserService user = (UserService)cglib.getCglibProxy();
user.printUserName(1L); //执行方法
}
}
这些题目可以帮助你巩固反射机制的基本使用,同时也可扩展你的编程能力。好好思考这些问题,动手实践一下,相信会对你的Java编程技能有所提升。
相关推荐
- 前端入门——css 网格轨道详细介绍
-
上篇前端入门——cssGrid网格基础知识整体大概介绍了cssgrid的基本概念及使用方法,本文将介绍创建网格容器时会发生什么?以及在网格容器上使用行、列属性如何定位元素。在本文中,将介绍:...
- Islands Architecture(孤岛架构)在携程新版首页的实践
-
一、项目背景2022,携程PC版首页终于迎来了首次改版,完成了用户体验与技术栈的全面升级。作为与用户连接的重要入口,旧版PC首页已经陪伴携程走过了22年,承担着重要使命的同时,也遇到了很多问题:维护/...
- HTML中script标签中的那些属性
-
HTML中的<script>标签详解在HTML中,<script>标签用于包含或引用JavaScript代码,是前端开发中不可或缺的一部分。通过合理使用<scrip...
- CSS 中各种居中你真的玩明白了么
-
页面布局中最常见的需求就是元素或者文字居中了,但是根据场景的不同,居中也有简单到复杂各种不同的实现方式,本篇就带大家一起了解下,各种场景下,该如何使用CSS实现居中前言页面布局中最常见的需求就是元...
- CSS样式更改——列表、表格和轮廓
-
上篇文章主要介绍了CSS样式更改篇中的字体设置Font&边框Border设置,这篇文章分享列表、表格和轮廓,一起来看看吧。1.列表List1).列表的类型<ulstyle='list-...
- 一文吃透 CSS Flex 布局
-
原文链接:一文吃透CSSFlex布局教学游戏这里有两个小游戏,可用来练习flex布局。塔防游戏送小青蛙回家Flexbox概述Flexbox布局也叫Flex布局,弹性盒子布局。它决定了...
- css实现多行文本的展开收起
-
背景在我们写需求时可能会遇到类似于这样的多行文本展开与收起的场景:那么,如何通过纯css实现这样的效果呢?实现的难点(1)位于多行文本右下角的展开收起按钮。(2)展开和收起两种状态的切换。(3)文本...
- css 垂直居中的几种实现方式
-
前言设计是带有主观色彩的,同样网页设计中的css一样让人摸不头脑。网上列举的实现方式一大把,或许在这里你都看到过,但既然来到这里我希望这篇能让你看有所收获,毕竟这也是前端面试的基础。实现方式备注:...
- WordPress固定链接设置
-
WordPress设置里的最后一项就是固定链接设置,固定链接设置是决定WordPress文章及静态页面URL的重要步骤,从站点的SEO角度来讲也是。固定链接设置决定网站URL,当页面数少的时候,可以一...
- 面试发愁!吃透 20 道 CSS 核心题,大厂 Offer 轻松拿
-
前端小伙伴们,是不是一想到面试里的CSS布局题就发愁?写代码时布局总是对不齐,面试官追问兼容性就卡壳,想跳槽却总被“多列等高”“响应式布局”这些问题难住——别担心!从今天起,咱们每天拆解一...
- 3种CSS清除浮动的方法
-
今天这篇文章给大家介绍3种CSS清除浮动的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。首先,这里就不讲为什么我们要清楚浮动,反正不清除浮动事多多。下面我就讲3种常用清除浮动的...
- 2025 年 CSS 终于要支持强大的自定义函数了?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!1.什么是CSS自定义属性CSS自...
- css3属性(transform)的一个css3动画小应用
-
闲言碎语不多讲,咱们说说css3的transform属性:先上效果:效果说明:当鼠标移到a标签的时候,从右上角滑出二维码。实现方法:HTML代码如下:需要说明的一点是,a链接的跳转需要用javasc...
- CSS基础知识(七)CSS背景
-
一、CSS背景属性1.背景颜色(background-color)属性值:transparent(透明的)或color(颜色)2.背景图片(background-image)属性值:none(没有)...
- CSS 水平居中方式二
-
<divid="parent"><!--定义子级元素--><divid="child">居中布局</div>...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)