目录
2.2 使用步骤(FileObserver 创建了一个线程):
一、process类
JAVA 中 process 类的使用
Process是一个抽象类 封装了一个进程
1.创建进程对象
创建 process
方法1:
Process p = Runtime.getRuntime().exec(cmd);
cmd 是字符串类型 也可以是字符串类型的数组 内容就是 命令行
方法2:
Process p =ProcessBuilder.start();
Process 类提供了子进程的输入流,子进程的输出流子进程的输入流,等待进程完成,检查进程的推出状态以及销毁进程的方法;创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中。
2.process方法
destroy() #杀掉子进程。
exitValue() #返回子进程的出口值。
InputStream getErrorStream() #获得子进程的错误流。
InputStream getInputStream() #获得子进程的输入流。
OutputStream getOutputStream() #获得子进程的输出流。
waitFor() #导致当前线程等待,如果必要,一直要等到由该 Process 对象表示的进程已经终止。
二、Java反射
反射是框架设计的灵魂
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
使用反射的步骤:
(1.得到class类对象。
(2.通过class对象得到 成员变量、方法、构造方法、包的对象。
(3.通过成员变量、方法的对象修改自己访问权限 ,通过构造方法对象得到类对象,下面调用成 员变量、方法时需要用到类对象。
(4.通过成员变量、方法对象的方法访问。
例子-成员变量(全):
package fanshe.field;
public class Student {
public Student(){
}
//**********字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
package fanshe.field;
import java.lang.reflect.Field;
/*
* 获取成员变量并调用:
*
* 1.批量的
* 1).Field[] getFields():获取所有的"公有字段"
* 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
* 2.获取单个的:
* 1).public Field getField(String fieldName):获取某个"公有的"字段;
* 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
*
* 设置字段的值:
* Field --> public void set(Object obj,Object value):
* 参数说明:
* 1.obj:要设置的字段所在的对象;
* 2.value:要为字段设置的值;
*
*/
public class Fields {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("fanshe.field.Student");
//2.获取字段
System.out.println("************获取所有公有的字段********************");
Field[] fieldArray = stuClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
fieldArray = stuClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("*************获取公有字段**并调用***********************************");
Field f = stuClass.getField("name");
System.out.println(f);
//获取一个对象
Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
//为字段设置值
f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
//验证
Student stu = (Student)obj;
System.out.println("验证姓名:" + stu.name);
System.out.println("**************获取私有字段****并调用********************************");
f = stuClass.getDeclaredField("phoneNum");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "18888889999");
System.out.println("验证电话:" + stu);
}
}
例子-方法(简):
Class stuClass = Class.forName("fanshe.method.Student");
Method m = stuClass.getMethod();
Object obj = stuClass.getConstructor().newInstance();
m.invoke(obj, "刘德华");
1.Class类
必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
1、获取Class对象的三种方式及优缺点
1.1 Class class = Object.getClass();
1.2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
1.3 通过Class类的静态方法:forName(String className)(常用)
优缺点:
三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
2.Constructor类
1.使用步骤:
a.Constructor[] con = class.getConstructors();#得到一堆构造方法,可以选用其他方法返回特定构造方法。
b.Object object = Constructor.newInstance(Object... initargs);#即可得到原对象。
2.介绍:
1.获取构造方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用构造方法:
Object object = Constructor.newInstance(Object... initargs);Object... initargs为构造方法的参数。
2、 newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:newInstance(Object... initargs)
Object object = Constructor.newInstance(Object... initargs);Object... initargs为构造方法的参数。
可看可不看:使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用。
3.field类
使用步骤:
Class class = forName(String className)#略
Field f = class.getField("name");#得到name的属性对象
Object obj = class.getConstructor().newInstance();#略
f.setAccessible(true);#暴力反射,解除私有限定
f.set(obj, "18888889999");#name属性赋值
4.Method类
使用步骤:
Method method = stuClass.getMethod("show1", String.class);#
method = stuClass.getDeclaredMethod("show4", int.class);//调用制定方法(所有包括私有的),需要传入两个参数,第一个是调用的方法名称,第二个是方法的形参类型,切记是类型。
Object obj = stuClass.getConstructor().newInstance();
method.setAccessible(true);//解除私有限定
method.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
三、监控目录
1.Java中的用法(简略)
方法:
1.1、自己写代码,递归遍历
1.2、使用common-io(内部实现递归遍历)
1.3、使用WatchService(jdk提供的)
1.4、jnotify(直接调用window、Linux的api,需要拷贝dll或者so文件到对应目录下,效率非常高)
2.android中的用法-FileObserver类
2.1 概念
ContentObserver可以监听不同程序间指定uri或者cursor内容的变化,如果两个无网络连接的设备通过OTG线相连,并且两设备可以通过U盘路径的方式相互访问存储,那么两设备的不同应用通信可以尝试通过FileObserver或者ContentObserver来进行。
FileObserver是一个抽象类,可以创建FileObserver一个子类并且重写onEvent抽象方法来实现功能逻辑。android10(sdk版本29)之前,FileObserver有两个构造函数
public FileObserver(String path) {
this(path, ALL_EVENTS);
}
public FileObserver(String path, int mask) {
m_path = path;
m_mask = mask;
m_descriptor = -1;
}
android10开始,上面有路径参数的构造函数被废弃掉,新增了以文件和文件集合为参数的构造方法。这里需要区分当前设备版本去有效的调用路径或者文件的构造函数,否则低版本找不到相应的构造函数导致应用挂掉。
public FileObserver(@NonNull File file, @NotifyEventType int mask) {
this(Arrays.asList(file), mask);
}
public FileObserver(@NonNull List<File> files, @NotifyEventType int mask) {
mFiles = files;
mMask = mask;
}
2.2 使用步骤(FileObserver 创建了一个线程):
(1.由于FileObserver是抽象类,编写类继承,重写onEnvet()函数 :class MyFileObserver extends FileObserver{.......};编写类继承
(2.实例化继承类;myFileObserver=new MyFileObserver(new File("/sdcard/test.txt")) ;
(3.开启监控:myFileObserver.startWatching();
(4.退出时要关闭监控:myFileObserver.stopWatching();
当有事件来临时会调用onEnevt()函数。
2.3 实例代码:
public class MyFileObserver extends FileObserver {
private static final String TAG = "MyFileObserverLog";
public MyFileObserver(File file) {
super(file.getAbsolutePath(), FileObserver.ALL_EVENTS);
Log.d(TAG, "MyFileObserver: "+file.getAbsolutePath()+",,"+FileObserver.ALL_EVENTS);
}
@Override
public void onEvent(int event, String path) {
Log.d(TAG, "onEvent path:"+ path+",event="+event);
switch (event){
case FileObserver.CREATE:
break;
}
}
}
public class MainActivity extends AppCompatActivity {
MyFileObserver myFileObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},22);
}
myFileObserver=new MyFileObserver(new File("/sdcard/test.txt")) ;
myFileObserver.startWatching();
FileProvider.getUriForFile()
}
@Override
protected void onDestroy() {
myFileObserver.stopWatching();
super.onDestroy();
}
}
修改文件内容,log打印如下,可以过滤对自己有用的event即可
2020-04-03 18:24:11.977 6173-6209/com.adups.myapplication D/MyFileObserverLog: onEvent path:null,event=2
2020-04-03 18:24:11.977 6173-6209/com.adups.myapplication D/MyFileObserverLog: onEvent path:null,event=32
2020-04-03 18:24:12.040 6173-6209/com.adups.myapplication D/MyFileObserverLog: onEvent path:null,event=2
2020-04-03 18:24:12.043 6173-6209/com.adups.myapplication D/MyFileObserverLog: onEvent path:null,event=2
2020-04-03 18:24:12.046 6173-6209/com.adups.myapplication D/MyFileObserverLog: onEvent path:null,event=8
上面日志对应id
public static final int MODIFY = 0x00000002;
public static final int OPEN = 0x00000020;
public static final int CLOSE_WRITE = 0x00000008;
谷歌推荐为了保证FileObserver不被垃圾回收,最好将FileObserver保定在一个长生命周期对象上,比如sevice,或者Application。
四、Random类
在JDK的java.util包中有一个Random类,可以在指定的取值范围内随机产生数字。在Random类中有两种构造方法,如下:
Random() //无参构造方法,用于创建一个伪随机数生成器。
Random(long seed) //有参构造方法,使用一个long类型的seed种子创建伪随机数生成器。
例子:
import java.util.Random;
public class Main{
public static void main(String[] args)throws Exception{
Random r=new Random(); //不传入种子
for(int i=0;i<8;i++){
System.out.println(r.nextInt(100));
}
}
}
上边两个截图说明同样的程序运行两次得到的结果并不相同,是因为在创建Random对象时没有传入种子参数,程序会自动以当前时间为时间戳。所以每一次的运行结果都是不同的。若传入种子则相同。