什么是java反射机制?

类的正常加载

image

反射概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Class对象的由来是将class文件读入内存,并为之创建一个Class对象。


反射

如果不知道某个对象的确切类型,RTTI可以告诉你。但是有一个前提条件:这个类型在编译时必须已知,这样才能使用RTTI识别它。换句话说,在编译时,编译器必须知道所有要通过RTTI来处理的类。

人们想要在运行时获取类的信息的另一个动机,便是希望提供在跨网络的远程平台上创建和运行对象的能力。这被称为远程方法调用(RMI),它允许一个java程序将对象分布到多台机器上

Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Field、Method以及Constructor类(每个类都实现了Member接口)

这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。

  • 使用Constructor创建新的对象
  • get()和set()方法读取和修改与Field对象关联的字段
  • 用invoke()方法调用与Method对象关联的方法
  • getField()、getMethod()、getConstructors()返回字段、方法、以及构造器的对象的数组

这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

反射机制总结:通过反射与一个未知类型的对象打交道是,JVM只是简单地检查这个对象,看它属于哪个特定的类。在用它做其他事情之前必须先加载那个类的Class对象。因此,那个类的.class文件对于JVM来说是必须获取的:要么在本地机器上,要么可以通过网络取得。

RTTI与反射之间真正的区别:

  • 对RTTI来说,编译器在编译时打开和检查.class文件。(用普通方式调用对象的所有方法)
  • 对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件。

动态代理

代理是基本的设计模式之一。它是为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信。因此代理充当着中间人的角色。

public interface Interface {
	void doSomething();
	void somethingElse(String arg);
}
//实际对象
public class RealObject implements Interface{

	@Override
	public void doSomething() {
		// TODO Auto-generated method stub
		System.out.println("doSomething");
	}

	@Override
	public void somethingElse(String arg) {
		// TODO Auto-generated method stub
		System.out.println("somethingElse "+arg);
	}

}
//代理
public class SimpleProxy implements Interface{
	private Interface proxied;
	public SimpleProxy(Interface proxied){
		this.proxied = proxied;
	}
	@Override
	public void doSomething() {
		// TODO Auto-generated method stub
		System.out.println("SimpleProxy doSomething");
		proxied.doSomething();
	}

	@Override
	public void somethingElse(String arg) {
		// TODO Auto-generated method stub
		System.out.println("SimpleProxy somethingElse "+arg);
		proxied.somethingElse(arg);
	}
}

使用代理场景:在任何时刻,只要你想要将额外的操作从“实际”对象中分离到不同的地方,并且很容易做出修改。

java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定响应的对策。

public class DynamicProxyHandler implements InvocationHandler{
	private Object proxied;
	public DynamicProxyHandler(Object proxied){
		this.proxied = proxied;
	}
	@Override
	public Object invoke(Object proxy, Method method,
			Object[] args) throws Throwable {
		System.out.println("*** proxy: "+proxy.getClass()+", method: "+method+", args: "+args);
		if(args != null){
			for(Object arg:args){
				System.out.println(" "+arg);
			}
		}
		return method.invoke(proxied, args);
	}
}
public class SimpleDynamicProxy{
	public static void consumer(Interface iface){
		iface.doSomething();
		iface.somethingElse("test");
	}
	public static void main(String[] args) {
		RealObject real = new RealObject();
		consumer(real);
		Interface proxy = (Interface)Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class},
				new DynamicProxyHandler(real));
		consumer(proxy);
	}
}
output:
doSomething
somethingElse test
*** proxy: class $Proxy0, method: public abstract void com.test.Interface.doSomething(), args: null
doSomething
*** proxy: class $Proxy0, method: public abstract void com.test.Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@2ce83912
 test
somethingElse test

调用Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递给一个“实际”对象的引用,从而使得调用处理器在执行中介任务时,可以将请求转发。


反射

要想理解动态代理的实现原理,我们还得先来理解反射。什么是反射呢?一般我们操作一个对象时,都会先new一个,比如现在有一个Person类:

public class Person {
    public String name;
    private int age;
    public Person(String name){
        System.out.print("有参数实例化\n");
        this.name = name;
    }
    public Person(){
        System.out.print("无参数实例化\n");
    }
    
    private Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void run(){
        System.out.print("跑步");
    }
    public String getName() {
        return name;
    }
}

如上,我们定义了一个Person类,里面定义了几个构造方法,一个有参数一个没有,还有一个私有的带参数的构造方法,另外还有两个方法,一个方法为获取Person的名字,一个是让这个Person跑步,如果我们希望让一个Person跑起来,该怎么做呢,很简单,我们只需要new 一个Person对象,然后调用其run方法就可以了,如下:

Person perosn = new Person("张三");
person.run();

这样就让一个Person跑起来了,但是问题来了,如果在程序运行的时候,我需要操作的不一定是Person,而是一个会变得类,这个类可能是Person也可能是其他类比如叫做Bird或者Dog等等,而我们要操作的方法也不一定是run,也有可能是fly,sleep等等其他方法。那这时怎么办,很显然,我们是无法事先new 一个对象,因为我们根本就不知道程序运行的时候需要操作什么对象,执行什么方法,这时我们就可以用上反射了,反射可以使你在运行时读取类或对象的信息,也可以在运行时创建对象,操作对象的字段属性与方法。

好了理解了什么是反射,接下来,我们来看下如何使用反射。要想使用反射,你需要用到一个类,即Class类。什么是Class类呢?我们知道Java和C语言最大的不同就是,C是面向过程的,而Java是面向对象的。在Java的世界里,一切皆对象,一切都是可描述的,只要你能想到的,不管什么,我们都可以用类来描述,那么问题来了,我们知道类也是客观存在的东西,那么用什么来描述类的,答案就是Class类,即一个描述类的类,这个类的名字为Class。这是一个实际存在的类,路径为JDK的java.lang包中,感兴趣的朋友可以去看下。所谓存在即合理,这个Class类肯定不是Java工程师闲的蛋疼写出来的,而是有用的,拿上面的Person类举个例子,一开始我们通过编码生成了一个Person.java文件,然后通过编译又生成了一个Person.class字节码文件,这个文件就保存了一个Class对象,对象中包含了Person类的所有信息,当我们调用new Person()时,虚拟机就会检查内存中是否加载了Person.class这个字节码文件,如果没有就会加载,此时这个Class对象也会被加载到内存中,当虚拟机实例化Person对象时,虚拟机需要知道一些信息,比如要实例化的类中有什么字段什么方法等等,这些信息都被保存在Class对象中。所以说Class类对于虚拟机来说是个很重要的类。同样在反射中,我们也需要知道Person类的信息,这自然就离不开Class对象。

那么我们如何获取到Class类的对象呢,一共有三种方式,拿上面Person类举例子:
第一种,Class类有一个forName(String className)方法,需要传入一个类的完整类名,返回为该类型的Class对象,如下:

Class clazz = Class.forName("包名.Person");

注意,调用forName时,你需要捕获一个叫做ClassNotFoundException无法找到该类的异常。

第二种,你需要先创建一个Person对象,然后调用Person对象的getClass方法,就可以获取到Class对象:

Person person = new Person("张三");
Class clazz = person.getClass();

这种方式不足的地方在于获取Class对象前你还要创建一个Person对象。

第三种,最简单也是最安全的一种方式为直接调用Person.class,如下:

Class clazz = Person.class;

以上简单说明了下获取Class对象的几种方式,我们之前说过Class对象保存了对应类的类信息,包括这个类的构造方法、字段属性,类中的方法等。接下来我们来看下,如何使用Class对象来获取以及操作这些类信息。

构造方法Constructor

首先我们来看下构造方法,在反射中要想实例化一个类其实还是调用该类构造方法,只不过不是简单new下就可以了。我们先来看一种简单的实例化方式:

Class<?> clazz = Class.forName("包名.Person");
Person person = (Person) clazz.newInstance();
person.run();

上面的代码很简单,我们先调用Class的forName方法来获取Person类的Class对象,然后直接调用该对象的newInstance方法,这样就获取到了一个Person实例,然后调用他的run方法:

输出结果
====================================
无参数实例化
跑步
====================================

可以看到Person的构造方法成功被调用了,不过需要注意的是clazz.newInstance只适用于无参数构造方法,有参的我们需要通过Class获取Constructor对象来操作,Constructor对象是对构造方法的封装,Class获取Constructor对象的主要方法有以下几种:

返回值方法名称说明
ConstructorgetConstructor(Class<?>… parameterTypes)返回指定参数类型、具有public访问权限的构造函数对象
Constructor<?>[]getConstructors()返回所有具有public访问权限的构造函数的Constructor对象数组
ConstructorgetDeclaredConstructor(Class<?>… parameterTypes)返回指定参数类型、所有声明的(包括private)构造函数对象
Constructor<?>[]getDeclaredConstructor()返回所有声明的(包括private)构造函数对象
1. getConstructor(Class<?>… parameterTypes)

这个方法返回权限为public的构造方法对象,需要传入参数类型的Class对象,比如我们想要调用Person类中的Person(String name)构造方法可以通过以下方式来实现:

Class<?> clazz = Class.forName("com.modoutech.designpattern.Person");
Constructor<Person> constructor = (Constructor<Person>) clazz.getConstructor(String.class);
Person person1 = constructor.newInstance("张三");
person1.run();

可以看到我们先获取了Person的Class对象,然后调用Class的getConstructor方法,同时传入String.class参数,因为我们要调用的构造方法参数为String类型的,这样就得到了一个Constructor对象,接着我们就可以调用Constructor对象的newInstance方法并传入name参数,来实例化一个Person对象,获取到Perosn对象,就可以调用里面的方法啦。

2. getConstructors()

这个方法会返回所有权限为public的构造方法的Constructor对象数组。

Constructor<Person>[] constructors = (Constructor<Person>[]) clazz.getConstructors();
for (int i = 0; i < constructors.length; i++) {
    System.out.println("构造函数["+i+"]:"+constructors[i].toString() );
}
--------------------------------------------------
输出结果:
构造函数[0]:public com.modoutech.designpattern.Person()
构造函数[1]:public com.modoutech.designpattern.Person(java.lang.String)
--------------------------------------------------

可以看到我们获取了两个Constructor对象,这两个也正是对应了Person中权限为public的构造方法,至于接下来对这两个构造方法调用和上面的方法同理这里就不在赘述了。

3. getDeclaredConstructor(Class<?>… parameterTypes)

这个方法范围要大点,会返回类中申明的任何构造方法对象,包括权限为private的。比如我们想调用Person中私有的Person(String name,int age)构造方法,可以通过如下方式:

Constructor<Person> constructor = (Constructor<Person>) clazz.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Person person1 = constructor.newInstance("张三",23);
person1.run();

这里基本和上述步骤相同,不过需要注意的是访问私有的构造方法时,我们需要调用Constructor的setAccessible方法,并设置为true,表示可以访问该私有构造方法。

4. getDeclaredConstructor()

这个方法获取类中已申明的所有构造方法对象数组,包括private的,具体操作方法与上述相同,这里不再赘述。

好了这样我们简单的介绍了用Constructor在反射中实例化对象的几种方式,说完构造方法,接下来我们来看下如何获取以及操作类中的字段属性

字段Field

如果我们要想操作类或对象中的字段,那么就需要用到Field对象。同样这个Field对象也是通过Class获取的,以下是Class获取Field对象的几种方法:

返回值方法名称说明
FieldgetDeclaredField(String name)获取指定name名称的(包含private修饰的)字段,不包括继承的字段
Field[]getDeclaredField()获取Class对象所表示的类或接口的所有(包含private修饰的)字段,不包括继承的字段
FieldgetField(String name)获取指定name名称、具有public修饰的字段,包含继承字段
Field[]getField()获取修饰符为public的字段,包含继承字段

为了演示方便我们再创建一个Student类,继承自上述的Person类:

public class Student extends Person {
    private String course;
    public int score;

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }
}
1.getDeclaredField(String name)

获取指定名称的(包含private修饰的)字段,不包括从父类中继承的字段。

用这个方法,我们可以在Student类中,获取course和score字段,但是无法获取它父类Person中的字段。拿course举个例子:

Class<?> clazz = Class.forName("com.modoutech.designpattern.Student");
Student student = (Student) clazz.newInstance();
Field courseField = clazz.getDeclaredField("course");
courseField.setAccessible(true);
courseField.set(student,"语文");
System.out.print("course is "+student.getCourse());
-------------------------
输出结果:
无参数实例化
course is 语文
-------------------------

上述,我们先获取了Student的Class对象,并实例化一个Student对象,然后通过Class的getDeclaredField方法,并传入course这个字段名,然后获取一个Field对象,由于course这个字段为private,所以还需要调用他的setAccessible并传入true,来打开它的访问权限,之后就可以调用Field的set方法来设置这个字段的值,这个set方法需两个参数,第一个为需要设置的实例对象,第二个为需要设置的字段值。这样我们就完成了对course这个字段的赋值操作。

2. getDeclaredField()

这个方法用于获取Class对象所表示的类或接口的所有(包含private修饰的)字段,不包括继承的字段:

Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    System.out.print(fields[i].getName()+"\n");
}
---------------------------------------------
输出结果:
course
score
---------------------------------------------

以上我们获取了字段数组,并打印了每个字段名,可以看到我们只获取到了Student类中的course和score字段,并没有他父类的字段。

3. getField(String name)

这个方法获取指定名称的public字段,包括父类中的也可以获取到。接下来我们试着获取下Student父类中的name字段:

Class<?> clazz = Class.forName("com.modoutech.designpattern.Student");
Student student = (Student) clazz.newInstance();
Field field = clazz.getField("name");
field.set(student,"张三");
System.out.print("学生名字:"+student.getName());

---------------------------------------------------------------------------
输出结果:
无参数实例化
学生名字:张三
--------------------------------------------------------------------------

可以看到我们成功获取了Student父类中的字段,并做了赋值操作。

4. getField()

这个方法时获取所有public字段,包括父类中的:

Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
    System.out.print("字段名:"+fields[i].getName()+"\n");
}

---------------------------------------------------------------
输出结果:
字段名:score
字段名:name
---------------------------------------------------------------

可以看到,我们获取到了Student中声明的public字段score,同时还获取到了其父类中public字段name,至于对获取到的字段进行进一步的操作,和上面的一样,就不在赘述了。

在上面,可以看到,我们调用了Field 的set方法来设置字段的值,当然除了set方法外,Field还有其他的一些方法,部分方法如下:

方法返回值方法名称方法说明
Objectget(Object obj)返回指定对象上此 Field 表示的字段的值
Class<?>getType()返回一个 Class 对象,它标识了此Field 对象所表示字段的声明类型。
booleanisEnumConstant()如果此字段表示枚举类型的元素则返回 true;否则返回 false
StringtoGenericString()返回一个描述此 Field(包括其一般类型)的字符串
StringgetName()返回此 Field 对象表示的字段的名称
Class<?>getDeclaringClass()返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段

Method(方法)

如果我们想要操作类中的某个方法,我们可以借助Method这个类,这个类是对类或接口中某个方法的描述,我们可以通过调用Class对象的以下方法来获取Method对象:

返回值方法名称说明
MethodgetDeclaredMethod(String name, Class<?>… parameterTypes)返回一个指定参数的Method对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method[]getDeclaredMethod()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
MethodgetMethod(String name, Class<?>… parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method[]getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

以上简单的列举了获取Method对象的一些方法,具体获取方式就不演示了,和上面的操作步骤差不多。

接下来,我们来看下如何利用Method对象来调用类中方法。拿上面Person类举个例子,来看下如果通过Method来调用里面的run方法:

Class<?> clazz = Class.forName("com.modoutech.designpattern.Student");
Person person = (Person) clazz.newInstance();
Method method = clazz.getDeclaredMethod("run");
method.invoke(person);

---------------------------------------------
输出结果:
无参数实例化
跑步
---------------------------------------------

可以看到我们成功通过反射来调用了Person中的run方法,当然如果这个方法是private的,那么在调用该方法前需要调用Method的setAccessible方法,并传入true来打开该方法的访问权限。

当然除了上述介绍的一些方法外,Method还提供了其他的一些方法:

方法返回值方法名称方法说明
Objectinvoke(Object obj, Object… args)对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
Class<?>getReturnType()返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型,即方法的返回类型
TypegetGenericReturnType()返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象,也是方法的返回类型。
Class<?>[]getParameterTypes()按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。即返回方法的参数类型组成的数组
Type[]getGenericParameterTypes()按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的,也是返回方法的参数类型
StringgetParameterTypes()按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。即返回方法的参数类型组成的数组
Class<?>[]getName()以 String 形式返回此 Method 对象表示的方法名称,即返回方法的名称
booleanisVarArgs()判断方法是否带可变参数,如果将此方法声明为带有可变数量的参数,则返回 true;否则,返回 false。
StringtoGenericString()返回描述此 Method 的字符串,包括类型参数。

以上就是一些常用的方法,这里就不一一展开来讲了,如果想更详细的了解可以查阅官方API。


反射应用

1.反射main方法

/**
 * 该类用于测试main方法
 */
public class Student {

    public static void main(String[] args) {
        System.out.println("main方法执行了。。。");
    }
}
/**
 * 获取Student类的main方法、不要与当前的main方法搞混了
 */
public class Main {

    public static void main(String[] args) {
        try {
            //1、获取Student对象的字节码
            Class clazz = Class.forName("fanshe.main.Student");

            //2、获取main方法
             Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,
            //3、调用main方法
            // methodMain.invoke(null, new String[]{"a","b","c"});
             //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
             //这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
             methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
            // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.反射运行配置文件内容

3.通过反射越过泛型检查

/*
 * 通过反射越过泛型检查
 * 
 * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
 */
public class Demo {
    public static void main(String[] args) throws Exception{
        ArrayList<String> strList = new ArrayList<>();
        strList.add("aaa");
        strList.add("bbb");

    //  strList.add(100);
        //获取ArrayList的Class对象,反向的调用add()方法,添加数据
        Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
        //获取add()方法
        Method m = listClass.getMethod("add", Object.class);
        //调用add()方法
        m.invoke(strList, 100);

        //遍历集合
        for(Object obj : strList){
            System.out.println(obj);
        }
    }
}
output:
aaa
bbb
100

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/163155.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多因素方差分析(Multi-way Analysis of Variance) R实现

1, data0507 flower 是某种植物在两个海拔和两个气温下的开花高度&#xff0c;采用合适 的统计方法&#xff0c;检验该种植物的开花高度在不同的海拔之间和不同的气温之间有无差异&#xff1f;如果有差异&#xff0c;具体如何差异的&#xff1f;&#xff08;说明依据、结论等关…

网络运维与网络安全 学习笔记2023.11.18

网络运维与网络安全 学习笔记 第十九天 今日目标 冲突域和交换机工作原理、广播域和VLAN原理 VLAN配置、TRUNK原理与配置、HYBRID原理与配置 冲突域和交换机工作原理 冲突域概述 定义 网络设备发送的数据&#xff0c;产生冲突的区域&#xff08;范围&#xff09; 对象 “数…

开源情报 (OSINT)

开源情报 (OSINT)是出于情报目的收集和分析公开数据的行为。 什么是开源数据&#xff1f; 开源数据是公众容易获得或可根据要求提供的任何信息。 OSINT 来源可包括&#xff1a; ▶ 报纸杂志文章以及媒体报道▶ 学术论文和发表的研究▶ 书籍和其他参考资料▶ 社交媒体活动▶…

rabbitmq默认交换机锁绑定的routingkey-待研究

例如这个是我的一个消息队列&#xff0c;它默认绑定的交换机是 什么类型呢? 看到这个图&#xff0c;感觉应该是一个默认的交换机&#xff0c;因为是default exchange 于是来到交换机来看看其他默认的交换机&#xff1a; 这里可以看到默认的交换机是direct&#xff08;应该没…

损失函数(Loss Function)与代价函数(Cost Function)、目标函数(Objective Function)区别

损失函数定义在单个样本上&#xff0c;算的是一个样本的误差。 代价函数定义在整个训练集上&#xff0c;是所有样本误差的平均&#xff0c;也就是损失函数的平均。 目标函数定义为最终需要优化的函数&#xff0c;等于经验风险 结构风险&#xff08;也就是Cost Function 正则化…

UE 调整材质UV贴图长宽比例

首先&#xff0c;为什么要先减去0.5呢&#xff0c;因为缩放的贴图中心在0,0原点&#xff0c;以这个点缩放效果是这样&#xff1a; 它缩放的图案不会在正中间&#xff0c;因为是以0,0点进行缩放的 以这个图的箭头去缩放图片的&#xff0c;所以不能使得缩放后的图片放在正中心 那…

<C++>类和对象下|初始化列表|explicit static|友元|内部类|匿名对象|构造函数的优化

文章目录 1. 初始化列表2. explicit关键字3. 友元3.1 友元函数3.2 友元类 4. static关键字4.1 概念4.2 特性 5.内部类5.1 概念5.2 特性 6. 匿名对象7. 拷贝构造时的优化 1. 初始化列表 在类的构造函数体中&#xff0c;对成员属性写的操作叫做赋值&#xff0c;那么成员的初始化…

深度学习数据集—细胞、微生物、显微图像数据集大合集

最近收集了一大波关于细胞、微生物、显微图像数据集&#xff0c;有细胞、微生物&#xff0c;细菌等。 接下来是每个数据的详细介绍&#xff01;&#xff01; 1、12500张血细胞增强图像&#xff08;JPEG&#xff09;数据集 该数据集包含12500张血细胞增强图像&#xff08;JPE…

实验(三):微程序计数器uPC实验

一、实验内容与目的 实验要求&#xff1a; 利用 CP226 实验仪上的 K16..K23 开关做为 DBUS 的数据&#xff0c;其它开关做为控制信号&#xff0c;实现微程序计数器 uPC 的写入和加1功能。 实验目的&#xff1a; 1、了解模型机中微程序的基本概念。 2、了解 uPC 的结构、工作原理…

windows nodejs 15.0.0下载安装

下载 Node v15.0.0 (Current) | Node.js (nodejs.org) 下载地址 https://nodejs.org/dist/v15.0.0/node-v15.0.0-x64.msi 安装 双击运行 等待安装完成 确认安装成功 管理员运行cmd 查看版本号

微信(小程序开发): 解决播放音乐没有声音的情况 代码不报错的情况下依旧没有声音的解决方案

解决无声的问题 在此之前&#xff0c;确保代码能够正常执行哈&#xff01;发这个其实没什么&#xff0c;就是有些人光写代码不调试出现了这个问题 其实解决方法特别简单 第一步&#xff1a; 打开项目后&#xff0c;点击三个点&#xff0c;然后选择模拟操作 第二步&#xff…

AIGC 是通向 AGI 的那条路吗?

AIGC 是通向 AGI 的那条路吗&#xff1f; 目录 一、背景知识 1.1、AGI&#xff08;人工通用智能&#xff09; 1.1.1、概念定义 1.1.2、通用人工智能特质 1.1.3、通用人工智能需要掌握能力 1.2、AIGC 二、AIGC 是通向 AGI 的那条路吗&#xff1f; 三、当前实现真正的 A…

python趣味编程-5分钟实现一个打字速度测试(含源码、步骤讲解)

Python速度打字测试是用 Python 编程语言编写的,速度打字测试 Python项目理念,我们将构建一个令人兴奋的项目,通过它您可以 检查 甚至 提高 您的打字速度。 为了创建图形用户界面(GUI),我们将使用 用于处理图形的pygame库。 Python 打字速度测试有利于学生或初学者提高…

基于动物迁徙算法优化概率神经网络PNN的分类预测 - 附代码

基于动物迁徙算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于动物迁徙算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于动物迁徙优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

问卷工具价格一览:合理定价,满足您的预算需求

在市场调研、市场营销和客户反馈收集等方面&#xff0c;问卷调查是一项重要而有效的工具。而在众多的问卷工具中&#xff0c;Zoho Survey以其丰富的功能和灵活的定价模式而备受关注。Zoho Survey的定价如何&#xff1f;今天我们来聊一聊。 Zoho Survey提供了多种定价方案&…

JRC Monthly Water History, v1.4数据集

简介&#xff1a; JRC Monthly Water History产品&#xff0c;是利用1984至2020年获取的landsat5、landsat7和landsat8的卫星影像&#xff0c;生成的一套30米分辨率的全球地表水覆盖的月度地表水监测地图集。该数据集共有442景数据&#xff0c;包含1984年3月至2020年12月间的月…

【心得】PHP的文件上传个人笔记

目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…

云课五分钟-0ALinux文件系统及权限-查询命令如何使用

前篇&#xff1a; 云课五分钟-09Linux基础命令实践-AI助力快速入门 视频&#xff1a; 云课五分钟-0ALinux文件系统及权限-查询命令如何使用 文本&#xff1a; Linux文件系统及权限示例教程&#xff08;Ubuntu&#xff09; 一、Linux文件系统基础 在Linux中&#xff0c;一切…

〖大前端 - 基础入门三大核心之JS篇㊲〗- DOM改变元素节点的css样式、HTML属性

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

WordPress主题WoodMart v7.3.2 WooCommerce主题和谐汉化版下载

WordPress主题WoodMart v7.3.2 WooCommerce主题和谐汉化版下载 WoodMart是一款出色的WooCommerce商店主题&#xff0c;它不仅提供强大的电子商务功能&#xff0c;还与流行的Elementor页面编辑器插件完美兼容。 主题文件在WoodMart Theme/woodmart.7.3.2.zip&#xff0c;核心在P…