Java基础——Java反射机制及IoC原理

一、概念


       主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

       反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

       类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。


二、作用


    1)在运行时判断任意一个对象所属的类;

    2)在运行时获取类的对象;

    3)在运行时访问java对象的属性,方法,构造方法等。


三、优点与缺点


       首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 

       静态编译:在编译时确定类型,绑定对象,即通过。 

       动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。

       反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

       比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

       反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。


四、示例


1、通过一个对象获取完整的包名和类名

注:所有类的对象其实都是Class类的实例

package Reflect;class Demo{//other codes...
}class hello{public static void main(String[] args) {Demo demo=new Demo();System.out.println(demo.getClass().getName());}
}
运行结果:

Reflect.Demo
2、实例化Class类对象
package Reflect;class Demo{//other codes...
}class hello{public static void main(String[] args) {Class<?> demo1=null;Class<?> demo2=null;Class<?> demo3=null;try{//一般尽量采用这种形式demo1=Class.forName("Reflect.Demo");}catch(Exception e){e.printStackTrace();}demo2=new Demo().getClass();demo3=Demo.class;System.out.println("类名称   "+demo1.getName());System.out.println("类名称   "+demo2.getName());System.out.println("类名称   "+demo3.getName());}
}
运行结果:

类名称   Reflect.Demo
类名称   Reflect.Demo
类名称   Reflect.Demo
3、通过Class实例化其他类的对象

package Reflect;class Person{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;}@Overridepublic String toString(){return "["+this.name+"  "+this.age+"]";}private String name;private int age;
}class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}Person per=null;try {per=(Person)demo.newInstance();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}per.setName("Rollen");per.setAge(20);System.out.println(per);}
}
运行结果:

[Rollen  20]

       但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:

比如定义了一个构造函数:

public Person(String name, int age) {               this.age=age;this.name=name;
}
然后继续运行上面的程序,会出现:
java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)
       所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数。

4、通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

package Reflect;import java.lang.reflect.Constructor;class Person{public Person() {   }public Person(String name){this.name=name;}public Person(int age){this.age=age;}public Person(String name, int age) {this.age=age;this.name=name;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString(){return "["+this.name+"  "+this.age+"]";}private String name;private int age;
}class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}Person per1=null;Person per2=null;Person per3=null;Person per4=null;//取得全部的构造函数Constructor<?> cons[]=demo.getConstructors();try{per1=(Person)cons[0].newInstance();per2=(Person)cons[1].newInstance("Rollen");per3=(Person)cons[2].newInstance(20);per4=(Person)cons[3].newInstance("Rollen",20);}catch(Exception e){e.printStackTrace();}System.out.println(per1);System.out.println(per2);System.out.println(per3);System.out.println(per4);}
}
运行结果:

[null  0]
[Rollen  0]
[null  20]
[Rollen  20]
5、返回一个类实现的接口
package Reflect;interface China{public static final String name="Rollen";public static  int age=20;public void sayChina();public void sayHello(String name, int age);
}class Person implements China{public Person() {}public Person(String sex){this.sex=sex;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic void sayChina(){System.out.println("hello ,china");}@Overridepublic void sayHello(String name, int age){System.out.println(name+"  "+age);}private String sex;
}class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}//保存所有的接口Class<?> intes[]=demo.getInterfaces();for (int i = 0; i < intes.length; i++) {System.out.println("实现的接口   "+intes[i].getName());}}
}
运行结果:

实现的接口   Reflect.China
(以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)
6、取得其他类中的父类
class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}//取得父类Class<?> temp=demo.getSuperclass();System.out.println("继承的父类为:   "+temp.getName());}
}
运行结果:

继承的父类为:   java.lang.Object
7、获得其他类中的全部构造函数
//这个例子需要在程序开头添加import java.lang.reflect.*;
class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}Constructor<?>cons[]=demo.getConstructors();for (int i = 0; i < cons.length; i++) {System.out.println("构造方法:  "+cons[i]);}}
}
运行结果:

构造方法:  public Reflect.Person()
构造方法:  public Reflect.Person(java.lang.String)
class hello{public static void main(String[] args) {Class<?> demo=null;try{demo=Class.forName("Reflect.Person");}catch (Exception e) {e.printStackTrace();}Constructor<?>cons[]=demo.getConstructors();for (int i = 0; i < cons.length; i++) {Class<?> p[]=cons[i].getParameterTypes();System.out.print("构造方法:  ");int mo=cons[i].getModifiers();System.out.print(Modifier.toString(mo)+" ");System.out.print(cons[i].getName());System.out.print("(");for(int j=0;j<p.length;++j){System.out.print(p[j].getName()+" arg"+i);if(j<p.length-1){System.out.print(",");}}System.out.println("){}");}}
}
运行结果:
构造方法:  public Reflect.Person(){}
构造方法:  public Reflect.Person(java.lang.String arg1){}

8、取得其他类的全部属性,将这些整理在一起,也就是通过class取得一个类的全部框架

class hello {public static void main(String[] args) {Class<?> demo = null;try {demo = Class.forName("Reflect.Person");} catch (Exception e) {e.printStackTrace();}System.out.println("===============本类属性========================");// 取得本类的全部属性Field[] field = demo.getDeclaredFields();for (int i = 0; i < field.length; i++) {// 权限修饰符int mo = field[i].getModifiers();String priv = Modifier.toString(mo);// 属性类型Class<?> type = field[i].getType();System.out.println(priv + " " + type.getName() + " "+ field[i].getName() + ";");}System.out.println("===============实现的接口或者父类的属性========================");// 取得实现的接口或者父类的属性Field[] filed1 = demo.getFields();for (int j = 0; j < filed1.length; j++) {// 权限修饰符int mo = filed1[j].getModifiers();String priv = Modifier.toString(mo);// 属性类型Class<?> type = filed1[j].getType();System.out.println(priv + " " + type.getName() + " "+ filed1[j].getName() + ";");}}
}
运行结果:

===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;
9、通过反射调用其他类中的方法
class hello {public static void main(String[] args) {Class<?> demo = null;try {demo = Class.forName("Reflect.Person");} catch (Exception e) {e.printStackTrace();}try{//调用Person类中的sayChina方法Method method=demo.getMethod("sayChina");method.invoke(demo.newInstance());//调用Person的sayHello方法method=demo.getMethod("sayHello", String.class,int.class);method.invoke(demo.newInstance(),"Rollen",20);}catch (Exception e) {e.printStackTrace();}}
}
运行结果:

hello ,china
Rollen  20

10、调用其他类的set和get方法

class hello {public static void main(String[] args) {Class<?> demo = null;Object obj=null;try {demo = Class.forName("Reflect.Person");} catch (Exception e) {e.printStackTrace();}try{obj=demo.newInstance();}catch (Exception e) {e.printStackTrace();}setter(obj,"Sex","男",String.class);getter(obj,"Sex");}/*** @param obj   操作的对象* @param att   操作的属性* */public static void getter(Object obj, String att) {try {Method method = obj.getClass().getMethod("get" + att);System.out.println(method.invoke(obj));} catch (Exception e) {e.printStackTrace();}}/*** @param obj   操作的对象    * @param att   操作的属性* @param value 设置的值* @param type  参数的属性* */public static void setter(Object obj, String att, Object value,Class<?> type) {try {Method method = obj.getClass().getMethod("set" + att, type);method.invoke(obj, value);} catch (Exception e) {e.printStackTrace();}}
}// end class
运行结果:

11、通过反射操作属性
class hello {public static void main(String[] args) throws Exception {Class<?> demo = null;Object obj = null;demo = Class.forName("Reflect.Person");obj = demo.newInstance();Field field = demo.getDeclaredField("sex");field.setAccessible(true);field.set(obj, "男");System.out.println(field.get(obj));}
}// end class
12、通过反射取得并修改数组的信息
import java.lang.reflect.*;class hello{public static void main(String[] args) {int[] temp={1,2,3,4,5};Class<?>demo=temp.getClass().getComponentType();System.out.println("数组类型: "+demo.getName());System.out.println("数组长度  "+Array.getLength(temp));System.out.println("数组的第一个元素: "+Array.get(temp, 0));Array.set(temp, 0, 100);System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));}
}
运行结果:

数组类型: int
数组长度  5
数组的第一个元素: 1
修改之后数组第一个元素为: 100
13、通过反射修改数组大小
class hello{public static void main(String[] args) {int[] temp={1,2,3,4,5,6,7,8,9};int[] newTemp=(int[])arrayInc(temp,15);print(newTemp);System.out.println("=====================");String[] atr={"a","b","c"};String[] str1=(String[])arrayInc(atr,8);print(str1);}/*** 修改数组大小* */public static Object arrayInc(Object obj,int len){Class<?>arr=obj.getClass().getComponentType();Object newArr=Array.newInstance(arr, len);int co=Array.getLength(obj);System.arraycopy(obj, 0, newArr, 0, co);return newArr;}/*** 打印* */public static void print(Object obj){Class<?>c=obj.getClass();if(!c.isArray()){return;}System.out.println("数组长度为: "+Array.getLength(obj));for (int i = 0; i < Array.getLength(obj); i++) {System.out.print(Array.get(obj, i)+" ");}}
}
运行结果:

数组长度为: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
数组长度为: 8
a b c null null null null null
14、动态代理
首先来看看如何获得类加载器:
class test{}
class hello{public static void main(String[] args) {test t=new test();System.out.println("类加载器  "+t.getClass().getClassLoader().getClass().getName());}
}
运行结果:

类加载器  sun.misc.Launcher$AppClassLoader

其实在java中有三种类类加载器:

    1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

    2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

    3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。

package Reflect;import java.lang.reflect.*;//定义项目接口
interface Subject {public String say(String name, int age);
}// 定义真实项目
class RealSubject implements Subject {@Overridepublic String say(String name, int age) {return name + "  " + age;}
}class MyInvocationHandler implements InvocationHandler {private Object obj = null;public Object bind(Object obj) {this.obj = obj;return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object temp = method.invoke(this.obj, args);return temp;}
}class hello {public static void main(String[] args) {MyInvocationHandler demo = new MyInvocationHandler();Subject sub = (Subject) demo.bind(new RealSubject());String info = sub.say("Rollen", 20);System.out.println(info);}
}
运行结果:

Rollen  20

类的生命周期

       在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载、链接、初始化这3个步骤完成。

       类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载一次。

链接就是把二进制数据组装为可以运行的状态。

链接分为校验,准备,解析这3个阶段:

    校验:一般用来确认此二进制文件是否适合当前的JVM(版本),

    准备:就是为静态成员分配内存空间,。并设置默认值

    解析:指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)。

       完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期。


五、IoC原理

Spring中的IoC的实现原理就是工厂模式加反射机制。


1、我们首先看一下不用反射机制时的工厂模式

/*** 工厂模式*/
interface fruit{public abstract void eat();
}class Apple implements fruit{public void eat(){System.out.println("Apple");}
}class Orange implements fruit{public void eat(){System.out.println("Orange");}
}
// 构造工厂类
// 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
class Factory{public static fruit getInstance(String fruitName){fruit f=null;if("Apple".equals(fruitName)){f=new Apple();}if("Orange".equals(fruitName)){f=new Orange();}return f;}
}class hello{public static void main(String[] a){fruit f=Factory.getInstance("Orange");f.eat();}
}
当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。
2、利用反射机制的工厂模式
package Reflect;interface fruit{public abstract void eat();
}class Apple implements fruit{public void eat(){System.out.println("Apple");}
}class Orange implements fruit{public void eat(){System.out.println("Orange");}
}class Factory{public static fruit getInstance(String ClassName){fruit f=null;try{f=(fruit)Class.forName(ClassName).newInstance();}catch (Exception e) {e.printStackTrace();}return f;}
}class hello{public static void main(String[] a){fruit f=Factory.getInstance("Reflect.Apple");if(f!=null){f.eat();}}
}

       现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

       使用反射机制的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

3、使用反射机制并结合属性文件的工厂模式(即IoC)
首先创建一个fruit.properties的资源文件:
apple=Reflect.Apple
orange=Reflect.Orange
然后编写主类代码:
package Reflect;import java.io.*;
import java.util.*;interface fruit{public abstract void eat();
}class Apple implements fruit{public void eat(){System.out.println("Apple");}
}class Orange implements fruit{public void eat(){System.out.println("Orange");}
}
//操作属性文件类
class init{public static Properties getPro() throws FileNotFoundException, IOException{Properties pro=new Properties();File f=new File("fruit.properties");if(f.exists()){pro.load(new FileInputStream(f));}else{pro.setProperty("apple", "Reflect.Apple");pro.setProperty("orange", "Reflect.Orange");pro.store(new FileOutputStream(f), "FRUIT CLASS");}return pro;}
}class Factory{public static fruit getInstance(String ClassName){fruit f=null;try{f=(fruit)Class.forName(ClassName).newInstance();}catch (Exception e) {e.printStackTrace();}return f;}
}class hello{public static void main(String[] a) throws FileNotFoundException, IOException{Properties pro=init.getPro();fruit f=Factory.getInstance(pro.getProperty("apple"));if(f!=null){f.eat();}}
}
运行结果:

Apple


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

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

相关文章

Ubuntu boost库文件安装编译

简单介绍 Boost库是为C语言标准库提供扩展的一些C程序库的总称&#xff0c;由Boost社区组织开发、维护.Boost向来有准标准库之称&#xff0c;很多新特性例如智能指针等都是先在boost中实现&#xff0c;后来被吸收到标准库之中. Boost实现了日志、算法、日期、地理、数学、线程…

Java基础——类加载机制及原理

一、什么是类的加载&#xff1f; 类的加载指的是将类的.class文件中的二进制数据读入到内存中&#xff0c;将其放在运行时数据区的方法区内&#xff0c;然后在堆区创建一个java.lang.Class对象&#xff0c;用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Cl…

在Ubuntu环境下使用vcpkg安装sqlite_orm包文件

Ubuntu安装vcpkg 从github下载vcpkg的安装包&#xff0c;在usr/local路径下面执行如下命令 git clone https://github.com/Microsoft/vcpkg.git cd vcpkg //进入源码目录 ./bootstrap-vcpkg.sh //执行./bootstrap-vcpkg.sh进行编译安装&#xff0c;这个过程很慢 编译安装好…

finally语句与return语句的执行顺序

网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行&#xff1f;很多人都说不是&#xff0c;当然他们的回答是正确的&#xff0c;经过我试验&#xff0c;至少有两种情况下finally语句是不会被执行的&#xff1a; try语句没有被执行到…

window电脑查看ssh公钥,以及将自己的公钥添加到Github等类似网站

查看本机的ssh公钥 使用命令 cd ~/.ssh使用命令 ls 可以看到 id_rsa id_rsa.pub known_hosts 三个文件&#xff0c;此处需要的是id_rsa.pub文件使用命令 cat id_rsa.pub 查看文件的内容拷贝这段内容 添加自己的公钥 进入账户的设置页面参照如下步骤&#xff0c;进入SSH Key…

java八大排序算法

一、概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采…

密钥安全性讨论之密钥分层管理结构

密钥分层管理结构 密钥的安全管理通常采用层次化的保护方法。密钥管理分层管理机制将密钥分为三层&#xff0c;即根密钥、密钥加密密钥和工作密钥下层密钥为上层密钥提供加密保护&#xff0c;采用分层的密钥结构有助于密钥的管理满足本规范的要求 工作密钥 工作密钥对本地保存…

windows安装 Git Large File Storage大文件下载工具ge

下载地址 导航到 git-lfs.github.com 并单击Download开始下载git-lfs的用法指南 验证安装成功 打开Git Bash验证安装成功&#xff0c;使用命令 git lfs install &#xff0c;如果出现 >Git LFS initlized&#xff0c;就代表安装成功参考链接 安装 Git Large File Storag…

Java基础——volatile关键字解析

简介volatile关键字虽然从字面上理解起来比较简单&#xff0c;但是要用好不是一件容易的事情。由于volatile关键字是与Java的内存模型有关的&#xff0c;因此在讲述volatile关键之前&#xff0c;我们先来了解一下与内存模型相关的概念和知识&#xff0c;然后分析了volatile关键…

Linux ubuntu对于cmake的版本更新

问题产生 在ubuntu环境下运行C代码&#xff0c;工程文件中CMakeLists文件显示要求cmake的版本最低是3.15&#xff0c;但是我的本地版本是3.11&#xff0c;虽然修改CMakelists文件为3.11也是可以编译通过&#xff0c;但是潜在的问题是未知的。 查看本地cmake的版本 cmake --ve…

Java基础——Java IO详解

一、概述 1、Java IO Java IO即Java 输入输出系统。不管我们编写何种应用&#xff0c;都难免和各种输入输出相关的媒介打交道&#xff0c;其实和媒介进行IO的过程是十分复杂的&#xff0c;这要考虑的因素特别多&#xff0c;比如我们要考虑和哪种媒介进行IO&#xff08;文件、控…

Java基础——Java NIO详解(二)

一、简介 在我的上一篇文章Java NIO详解&#xff08;一&#xff09;中介绍了关于标准输入输出NIO相关知识&#xff0c; 本篇将重点介绍基于网络编程NIO&#xff08;异步IO&#xff09;。 二、异步IO 异步 I/O 是一种没有阻塞地读写数据的方法。通常&#xff0c;在代码进行 rea…

Java基础——Java NIO详解(一)

一、基本概念 1、I/0简介 I/O即输入输出&#xff0c;是计算机与外界世界的一个借口。IO操作的实际主题是操作系统。在java编程中&#xff0c;一般使用流的方式来处理IO&#xff0c;所有的IO都被视作是单个字节的移动&#xff0c;通过stream对象一次移动一个字节。流IO负责把对象…

MAC上Git安装与GitHub基本使用

参考链接 MAC上Git安装与GitHub基本使用

Java基础——深入理解Java线程池

简介 我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低系统的效率&#xff0c;…

密码机项目安装软件时候出现的问题以及对应的解决办法

Could NOT find Boost (missing: locale) (found version "1.65.1") 使用命令 apt-get install libboost-locale-dev 进行安装 解决普通用户cmake版本11&#xff0c;而root用户版本15&#xff0c;clion对于版本兼容的问题 修改clion里面的toolchain&#xff0c;将其…

Java基础——线程及并发机制

前言 在Java中&#xff0c;线程是一个很关键的名词&#xff0c;也是很高频使用的一种资源。那么它的概念是什么呢&#xff0c;是如何定义的&#xff0c;用法又有哪些呢&#xff1f;为何说Android里只有一个主线程呢&#xff0c;什么是工作线程呢。线程又存在并发&#xff0c;并…

密码机 密钥管理项目安装配置 从零开始

安装gcc 更新sudo apt-get update下载gcc sudo apt-get install gcc参考链接 不推荐 安装g 下载g sudo apt-get install g 安装make sudo apt -get install make参考链接 安装cmake 下载地址参考链接 安装ssh sudo apt-get install ssh 安装git和配置 sudo apt-get inst…

Androud 如何有效减少重复代码

前言 重复的代码一直都是可维护性的大敌&#xff0c;重构的重要任务之一也就是要去除掉重复的代码&#xff0c;有效的减少重复代码&#xff0c;可以大大提高软件的扩展性。 在Android开发中&#xff0c;很容易产生重复的代码。因为Android是组件&#xff0c;模板式开发&#xf…