什么是java反射机制?

news2025/1/19 16:59:44

类的正常加载

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Filter和ThreadLocal结合存储用户id信息

ThreadLocal并不是一个Thread&#xff0c;而是Thread的局部变量。当使用ThreadLocal维护变量时&#xff0c;ThreadLocal为每个使用该变量的线程提供独立的变量副本&#xff0c;所以每一个线程都可以独立地改变自己的副本&#xff0c;而不会影响其它线程所对应的副本。ThreadLoc…

基于PI+重复控制的并网逆变系统谐波抑制策略模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; PI重复控制简介&#xff1a; 重复控制这一新型控制理论最早于出现日本学术界&#xff0c;其目的是为了用于解决质子加速器跟踪精度的问题。Yamamoto Y 等人提出了重复控制数学基础的内模原理&#xff0c;在控…

编写程序,要求输入x的值,输出y的值。分别用(1)不嵌套的if语句(2)嵌套的if语句(3)if-else语句(4)switch语句。

编写程序&#xff0c;要求输入x的值&#xff0c;输出y的值。分别用&#xff08;1&#xff09;不嵌套的if语句&#xff08;2&#xff09;嵌套的if语句&#xff08;3&#xff09;if-else语句&#xff08;4&#xff09;switch语句。 选择结构是编程语言中常用的一种控制结构&…

网工内推 | Linux运维,六险二金,最高30K,IE认证优先

01 上海域起 招聘岗位&#xff1a;Linux运维工程师 职责描述&#xff1a; 1.负责游戏产品运维相关的工作&#xff0c;流程文档、技术文档、功能脚本的编写整理 2.负责分析并排除系统、数据库、网络、应用等游戏产品运维中出现的故障及错误 3.负责对游戏产品项目进行线上部署、…

电磁场与电磁波part3--静态电磁场及其边值问题的解

1、当场源&#xff08;电荷、电流&#xff09;不随时间变化时&#xff0c;所产生的电场、磁场也不随时间变化&#xff0c;称为静态电磁场。静止电荷产生的静电场、在导电媒质中恒定运动电荷形成的恒定电场以及恒定电流产生的恒定磁场都属于静态电磁场。 2、静电场基本方程微分形…

Yolov5安装运行过程中出现的问题

Yolov5安装运行过程中出现的问题合集 安装问题pip 安装 requirements.txtcmd下如何退出python&#xff1f;升级numpy protobuf版本过高AttributeError: Can’t get attribute ‘SPPF’ on <module ‘models.common’ from 地址找不到图片NameError: name warnings is not de…

LabVIEW和NIUSRP硬件加快了认知无线电开发

LabVIEW和NIUSRP硬件加快了认知无线电开发 对于电视频谱&#xff0c;主用户传输有两种类型&#xff1a;广播电视和节目制作和特殊事件(PMSE)设备。广播塔的位置已知&#xff0c;且覆盖电视传输塔&#xff08;复用器&#xff09;附近的某个特定地理区域&#xff08;称为排除区域…

linux配置固定ip(两种方法)

首先刚下载的vm&#xff0c;刚创建的虚拟机&#xff0c;肯定是需要配置ip的 其次以前我的每次都是设置自动ip&#xff0c;这样每次登录都会自动获取ip地址&#xff0c;并且每次的ip都不相同。 ~方法&#xff1a; 开机登陆后 1)Cd /etc/sysconfig/network-scripts 2)Vi ifcf…

clion2020 中文版安装

一 程序安装 安装包地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1EJsmgmZcCQHoKDECkxmeaw?pwd1111 提取码&#xff1a;1111

Vue3+Vite实现工程化,插值表达式和v-text以及v-html

1、插值表达式 插值表达式最基本的数据绑定形式是文本插值&#xff0c;它使用的是"Mustache"语法&#xff0c;即 双大括号{{}} 插值表达式是将数据 渲染 到元素的指定位置的手段之一插值表达式 不绝对依赖标签&#xff0c;其位置相对自由插值表达式中支持javascript的…

Linux系统中sh脚本编写

文章目录 Linux系统中sh脚本编写1.在编写sh脚本前了解一下基本语法1.1 if语句单分支双分支多分枝 1.2 for语法 2. 自己写的demo &#xff1a;自动部署前端项目 &#xff08;自动拉取代码&#xff0c;打包&#xff0c;部署nginx&#xff09;3.定时执行 shell脚本 Linux系统中sh脚…

IO多路转接之select和poll

目录 一. IO多路转接的概念 二. 通过select实现IO多路转接 2.1 select接口 2.2 Select服务器的实现 2.3 select实现IO多路转接的优缺点 三. 通过poll实现IO多路转接 3.1 poll接口 3.2 Poll服务器的实现 3.3 poll实现IO多路转接的优缺点 四. 总结 一. IO多路转接的概念…

App测试入门

App测试基础知识 App测试&#xff0c;是指对移动应用软件&#xff08;如手机app、平板app等&#xff09;进行全面和系统的测试&#xff0c;以确保其功能、性能、安全性、稳定性、兼容性等方面能满足用户的使用需求和期望。 App常见运行系统 IOS系统&#xff1a; IOS系统是苹果公…

CUDA编程一、基本概念和cuda向量加法

目录 一、cuda编程的基本概念入门 1、GPU架构和存储结构 2、cuda编程模型 3、cuda编程流程 二、cuda向量加法实践 1、代码实现 2、代码运行和结果 有一段时间对模型加速比较感兴趣&#xff0c;其中的一块儿内容就是使用C和cuda算子优化之类一起给模型推理提速。之前一直…

适用于 Windows 的 10 个最佳视频转换器:快速转换高清视频

您是否遇到过由于格式不兼容而无法在您的设备上播放视频或电影的情况&#xff1f;您想随意播放从您的相机、GoPro 导入的视频&#xff0c;还是以最合适的格式将它们上传到媒体网站&#xff1f;您的房间里是否有一堆 DVD 光盘&#xff0c;想将它们转换为数字格式以便于播放&…

算法 LeetCode 题解 | 有效的括号

大家好&#xff0c;我是木川 一、题目描述 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。…

掌握Shell:从新手到编程大师的Linux之旅

1 shell介绍 1.1 shell脚本的意义 1.记录命令执行的过程和执行逻辑&#xff0c;以便以后重复执行 2.脚本可以批量处理主机 3.脚本可以定时处理主机 1.2 脚本的创建 #!/bin/bash # 运行脚本时候执行的环境1.3 自动添加脚本说明信息 /etc/vimrc # vim主配置文件 ~/.vimrc # 该…

Java之线程的概念及方法的学习

线程创建 方法一 直接使用Thread public class demo {public static void main(String[] args) {new Thread(){Overridepublic void run() {System.out.println(Thread.currentThread().getName());}}.start();System.out.println(Thread.currentThread().getName());} } main…

深信服AC应用控制技术

拓扑图 目录 拓扑图 一.上班时间不允许使用qq(假设上班时间是上午9到12&#xff0c;下午14到18) 1.新增上班时间不允许使用qq访问权限策略 2.将策略应用到组&#xff0c;例如修仙部 3.验证 上班时间发现登录不了 下班时间可以登录 二.上班时间不允许访问视频网站(假设上班时…

2023年优化算法之之霸王龙优化算法(TROA),原理公式详解,附matlab代码

霸王龙优化算法&#xff08;Tyrannosaurus optimization&#xff0c;TROA&#xff09;是一种新的仿生优化算法&#xff0c;该算法模拟霸王龙的狩猎行为&#xff0c;具有搜索速度快等优势。该成果于2023年发表在知名SCI期刊e-Prime-Advances in Electrical Engineering, Electro…