Java基础之深入理解Class对象与反射机制
深入理解Class对象
RRIT及Class对象的概念
RRIT(Run-Time Type Identification)运行时类型识别。在《Thinking in Java》一书第十四章中有提到,它的功能是在运行时识别对象的类型和类信息。有两种主要方式:“传统的”RTTI(它假定我们在编译时已经知道所有类型)和“反射”机制(它允许我们在运行时发现和使用类信息)。
类是程序的一部分,每个类都有一个类对象。换句话说,无论何时编写和编译新类,都会生成一个Class对象(更恰当地说,保存在相同名称的A.class文件中)。当第一次使用所有类时,它们都被动态地加载到JVM中。例如,我们编写了一个Test类并编译它来生成Test。班级。此时,Test类的Class对象保存在类文件中。当我们新建一个对象或引用一个静态成员变量时,Java虚拟机(JVM)中的类加载器子系统将相应的类对象加载到JVM中,然后JVM从这个类型的信息中创建我们需要的类对象,或者提供静态变量的参考值。应当注意,无论创建了多少实例对象,手动编写的每个类类类在JVM中都只有一个Class对象,也就是说,每个类在内存中都具有并且只有一个对应的Class对象。
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
如上所示,实际上JVM内存中只存有一个Test的Class对象。
Class类,类类也是Java中存在的一个真实类。JDK的Lang软件包。类类的实例表示Java应用程序运行时的类枚举或接口和注释(每个Java类运行时被表示为JVM中的类对象),类对象可以通过类名来获得。类,类型。getClass(),Class.forName(“类名”)。数组还映射到一个类对象,该类对象由具有相同元素类型和维度的所有数组共享。基本类型布尔、字节、char、.、int、long、float、double和关键词void也表示为类对象。
ublic final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000; private static native void registerNatives();
static {
registerNatives();
} /*
* Private constructor. Only the Java Virtual Machine creates Class objects. //私有构造器,只有JVM才能调用创建Class对象
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
到这我们也就可以得出以下几点信息:
Class类也是类的一种,与class关键字是不一样的。
手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件)
每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。
Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载
Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。
Class对象的加载及获取
Class对象的加载
正如我们前面提到的,类对象是由JVM加载的,所以什么时候加载呢?实际上,所有类在第一次使用时都动态地加载到JVM中。当程序创建对该类的第一个静态成员引用时,它加载使用的类(实际加载该类的字节码文件)。注意,使用新操作符创建类的新实例对象也被视为对类的静态成员(构造函数也是一个类)的引用。看来Java程序在开始运行之前没有完全加载到内存中,而且它们的所有部分都按需加载。因此,当使用这个类时,类加载器首先检查这个类的Class对象是否已经被加载(类的实例对象是根据Class对象中的类型信息创建的)。如果未加载,则默认的类加载Class对象将以相同的名称保存。编译后的类文件。当该类的字节码文件被加载时,它们必须接受相关的验证,以确保它们不被破坏,并且不包含坏的Java代码(这是Java的安全机制检测)。在没有问题之后,它们将被动态地加载到内存中,这相当于Cl。ass对象被加载到内存中(毕竟,类字节码文件保存Cl ass对象),并且还可以用于创建类的所有实例对象。
类加载的过程 :
1. 加载
在加载阶段,虚拟机需要完成3件事:
(1)通过一个类的全限定名(org/fenixsoft/clazz/TestClass)获取定义此类的二进制字节流(.class文件);
(2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
(3)在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口;
2. 验证
验证阶段是非常重要的,这个阶段是否严谨,直接决定了Java虚拟机是否能承受恶意代码的攻击,从执行性能的角度上讲,验证阶段的工作量在虚拟机的类加载子系统中又占了相当大的一部分。验证阶段大致上完成下面4个阶段的验证动作:
(1)文件格式验证
验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理;
这阶段的验证是基于二进制字节流进行的,只有通过了这个阶段的验证,字节流才会进入内存的方法区进行储存,所以后面的3个验证阶段全部是基于方法区的存储结构进行的,不会再直接操作字节流。
(2)元数据验证
对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求,保证不存在不符合Java语言规范的元数据信息;
(3)字节码验证
通过数据流和控制流分析,确定程序是语义是合法的、符合逻辑的,保证被校验的方法在运行时不会做出危害虚拟机安全的事件;
(4)符号引用验证
可以看作是对类自身以外(常量池中各种符号引用)的信息进行匹配性校验,确保解析动作能正常执行;
3. 准备
准备阶段是正式为类变量分配内存并设置类变量初始值阶段,这些变量所使用的内存都将在方法区中进行分配。这里进行内存分配仅仅是类变量(被static修饰的变量),而不包括实例变量,实例变量将在对象实例化时随着对象一起分配在Java堆中;
4. 解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、方法类型、方法句柄和调用点限定符7类符号引用进行;
5. 初始化
初始化阶段才真正开始执行类中定义的Java程序代码(或者说是字节码)。初始化是如何被触发的:
(1)遇到new、getstatic、putstatic或involestatic这4条指令时;
(2)使用 java.lang.reflect 包的方法对类进行反射调用的时候;
(3)初始化一个类时,如果父类还没被初始化,则先触发父类的初始化;
(4)虚拟机启动时,用户需要指定一个要执行的主类 (包含main()方法的那个类),虚拟机会先初始化这个主类;
(5)如果一个 java.lang.invoke.MethodHandle 实例最后解析的结果是 REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,若句柄所对应的类没有进行过初始化,则将它初始化;
上文源自《深入理解java虚拟机》一书,大家可以去读一下,这本书基本上是java程序猿学习必读之一了。在此就不深入展开了,因为这又是另一个JVM领域了。 以后如果写了该方面的文章,会贴到这里。
Class对象的获取
Class对象的获取主要有3种:
- 通过实例getClass()方法获取
- Class.forName方法获取
- 类字面常量获取
通过实例getClass()方法获取
Test t1 = new Test();
Class clazz=test.getClass();
System.out.println("clazz:"+clazz.getName());
getClass()是从顶级类Object继承而来的,它将返回表示该对象的实际类型的Class对象引用。
Class.forName方法获取
forName方法是Class类的静态成员方法,记住所有Class对象都源自这个Class类,因此Class类中定义的方法适用于所有Class对象。这里,通过forName方法,我们可以获得Test类的相应Class对象引用。注意,当调用forName方法时,您需要捕获一个名为ClassNotFoundException的异常,因为forName方法无法检测编译器中与其传递的字符串(是否有.class文件)对应的类的存在,并且只能在程序的运行时进行检查。如果不存在,将引发ClassNotFoundException异常。
使用forName方式会触发类的初始化,与之相比的是使用类字面常量获取
类字面常量获取
//字面常量的方式获取Class对象
Class clazz = Test.class;
这不仅更简单,而且更安全,因为它是在编译时检查的(因此不需要放在try语句块中)。而且它消除了对forName()方法的调用,因此也更有效。注意,当您使用“.“类”创建对Class对象的引用,Class对象不会自动初始化。注意,当您使用“.“类”创建对Classs对象的引用,Class对象不会自动初始化。使用该类的准备实际上包括三个步骤:
- 加载,这是由类加载器执行的,该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必需的),并从这些字节码中创建一个Class对象。
- 链接。在链接阶段将验证类中的字节码,为静态域分布存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
- 初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。
class Initable{
static final int staticFinal = 47;
static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);
static {
System.out.ptintln("Initializing Initable");
}
} class Initable2 {
static int staticNonFinal = 147;
static {
System.out.println("Initializing Initable2");
}
} class Initable3 {
static int staticNonFinal = 74;
static {
System.out.println("Initializing Initable3");
}
} public class ClassInitialization {
public static Random rand = new Random(47);
public static void main(String[] args) throws Exception {
Class initable = Initable.class;
System.out.println("After creating Initable ref");
System.out.println(Initable.staticFinal);
System.out.println(Initable.staticFinal2);
System.out.println(Initable2.staticNonFinal);
Clas initable3 = Class.forName("Initable3");
System.out.println("After creating Initable3 ref");
System.out.println(Initable3.staticNonFinal);
}
} /* output
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable ref
如果一个static final值是编译器常量
,就像Initable.staticFinal那样,那么这个值不需要对Initable类进行初始化就可以被读取。但是,如果只是将一个域设置为static和final的,还不足以确保这种行为,例如,对Initable.staticFinal2的访问将强制进行类的初始化,因为它不是一个编译期常量。
如果静态域不是最终的,则总是需要在读取之前进行链接(为域分配存储空间)和初始化(初始化存储空间),如访问Initable2所示。静态非决赛。从输出结果可以看出,通过文字常数获取获得的Initable类的Class对象不触发Initable类的初始化,这也验证了前面的分析。同时,还发现不可逆的。staticFinal变量不触发初始化,因为staticFinal在编译时属于静态常数,并且在编译阶段通过常数传播优化。公式将Initable类的常量staticFinal存储在一个名为NotInitialization类的常量池中。将来,对常量staticFinal of Initable类的引用实际上被转换成对其自己的常量NotInitialization类池的引用。因此,在编译之后,对编译时间常数的引用将在NotInitialization类的常量池中获得,这也是引用编译时间。静态常数不触发Initable类初始化的一个重要原因。然而,不适宜的。然后调用staticFinal2变量来触发Initable类的初始化。注意,尽管staticFinal2由static和final修改,但它的值在编译时无法确定。因此,staticFinal2不是编译时间常数,在使用此变量之前,必须初始化Initable类。Initable2和Initable3是静态成员变量,而不是编译时常数,引用触发初始化。至于forName方法获取Class对象,初始化被绑定到.,前面已经对此进行了分析。
instanceof与Class的等价性
关于instanceof 关键字,它返回一个boolean类型的值,意在告诉我们对象是不是某个特定的类型实例。如下,在强制转换前利用instanceof检测obj是不是Animal类型的实例对象,如果返回true再进行类型转换,这样可以避免抛出类型转换的异常(ClassCastException)
而isInstance方法则是Class类中的一个Native方法,也是用于判断对象类型的,看个简单例子:
事实上instanceOf 与isInstance方法产生的结果是相同的。
class A {} class B extends A {} public class C {
static void test(Object x) {
print("Testing x of type " + x.getClass());
print("x instanceof A " + (x instanceof A));
print("x instanceof B "+ (x instanceof B));
print("A.isInstance(x) "+ A.class.isInstance(x));
print("B.isInstance(x) " +
B.class.isInstance(x));
print("x.getClass() == A.class " +
(x.getClass() == A.class));
print("x.getClass() == B.class " +
(x.getClass() == B.class));
print("x.getClass().equals(A.class)) "+
(x.getClass().equals(A.class)));
print("x.getClass().equals(B.class)) " +
(x.getClass().equals(B.class)));
}
public static void main(String[] args) {
test(new A());
test(new B());
}
} /* output
Testing x of type class com.zejian.A
x instanceof A true
x instanceof B false //父类不一定是子类的某个类型
A.isInstance(x) true
B.isInstance(x) false
x.getClass() == A.class true
x.getClass() == B.class false
x.getClass().equals(A.class)) true
x.getClass().equals(B.class)) false
---------------------------------------------
Testing x of type class com.zejian.B
x instanceof A true
x instanceof B true
A.isInstance(x) true
B.isInstance(x) true
x.getClass() == A.class false
x.getClass() == B.class true
x.getClass().equals(A.class)) false
x.getClass().equals(B.class)) true
反射
反射机制是在运行状态下可以知道任何类的所有属性和方法,并且可以调用任何对象的任何方法和属性。获得的动态信息和对象的动态调用方法的功能被称为Java语言的反射机制。反射技术一直是爪哇的一个亮点,它也是大多数框架(如Spring/MybATIS等)要实现的骨干。在Java中,类类和Java。反射类库共同为反射技术提供了充分的支持。在反射包中,我们通常使用构造函数类来构造由类对象表示的类。通过使用Constructor类,我们可以在运行时动态创建对象以及由Class对象表示的Field类。通过使用Constructor类,我们可以在运行时动态修改成员变量(包括私有)和由Class对象表示的方法类的属性值。方法,通过该方法可以动态调用对象的方法(包括私有类),下面将分别解释这些重要的类。
Constructor类及其用法
Constructor类存在于反射包(java.lang.reflect)中,反映的是Class 对象所表示的类的构造方法。获取Constructor对象是通过Class类中的方法获取的,Class类与Constructor相关的主要方法如下:
下面看一个简单例子来了解Constructor对象的使用:
public class ConstructionTest implements Serializable {
public static void main(String[] args) throws Exception { Class<?> clazz = null; //获取Class对象的引用
clazz = Class.forName("com.example.javabase.User"); //第一种方法,实例化默认构造方法,User必须无参构造函数,否则将抛异常
User user = (User) clazz.newInstance();
user.setAge(20);
user.setName("Jack");
System.out.println(user); System.out.println("--------------------------------------------"); //获取带String参数的public构造函数
Constructor cs1 =clazz.getConstructor(String.class);
//创建User
User user1= (User) cs1.newInstance("hiway");
user1.setAge(22);
System.out.println("user1:"+user1.toString()); System.out.println("--------------------------------------------"); //取得指定带int和String参数构造函数,该方法是私有构造private
Constructor cs2=clazz.getDeclaredConstructor(int.class,String.class);
//由于是private必须设置可访问
cs2.setAccessible(true);
//创建user对象
User user2= (User) cs2.newInstance(25,"hiway2");
System.out.println("user2:"+user2.toString()); System.out.println("--------------------------------------------"); //获取所有构造包含private
Constructor<?> cons[] = clazz.getDeclaredConstructors();
// 查看每个构造方法需要的参数
for (int i = 0; i < cons.length; i++) {
//获取构造函数参数类型
Class<?> clazzs[] = cons[i].getParameterTypes();
System.out.println("构造函数["+i+"]:"+cons[i].toString() );
System.out.print("参数类型["+i+"]:(");
for (int j = 0; j < clazzs.length; j++) {
if (j == clazzs.length - 1)
System.out.print(clazzs[j].getName());
else
System.out.print(clazzs[j].getName() + ",");
}
System.out.println(")");
}
}
} class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
} /**
* 私有构造
* @param age
* @param name
*/
private User(int age, String name) {
super();
this.age = age;
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
} /* output
User{age=20, name='Jack'}
--------------------------------------------
user1:User{age=22, name='hiway'}
--------------------------------------------
user2:User{age=25, name='hiway2'}
--------------------------------------------
构造函数[0]:private com.example.javabase.User(int,java.lang.String)
参数类型[0]:(int,java.lang.String)
构造函数[1]:public com.example.javabase.User(java.lang.String)
参数类型[1]:(java.lang.String)
构造函数[2]:public com.example.javabase.User()
参数类型[2]:()
关于Constructor类本身一些常用方法如下(仅部分,其他可查API)
Field类及其用法
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。同样的道理,我们可以通过Class类的提供的方法来获取代表字段信息的Field对象,Class类与Field对象相关方法如下:
下面的代码演示了上述方法的使用过程
public class ReflectField { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class<?> clazz = Class.forName("reflect.Student");
//获取指定字段名称的Field类,注意字段修饰符必须为public而且存在该字段,
// 否则抛NoSuchFieldException
Field field = clazz.getField("age");
System.out.println("field:"+field); //获取所有修饰符为public的字段,包含父类字段,注意修饰符为public才会获取
Field fields[] = clazz.getFields();
for (Field f:fields) {
System.out.println("f:"+f.getDeclaringClass());
} System.out.println("================getDeclaredFields====================");
//获取当前类所字段(包含private字段),注意不包含父类的字段
Field fields2[] = clazz.getDeclaredFields();
for (Field f:fields2) {
System.out.println("f2:"+f.getDeclaringClass());
}
//获取指定字段名称的Field类,可以是任意修饰符的自动,注意不包含父类的字段
Field field2 = clazz.getDeclaredField("desc");
System.out.println("field2:"+field2);
}
/**
输出结果:
field:public int reflect.Person.age
f:public java.lang.String reflect.Student.desc
f:public int reflect.Person.age
f:public java.lang.String reflect.Person.name ================getDeclaredFields====================
f2:public java.lang.String reflect.Student.desc
f2:private int reflect.Student.score
field2:public java.lang.String reflect.Student.desc
*/
} class Person{
public int age;
public String name;
//省略set和get方法
} class Student extends Person{
public String desc;
private int score;
//省略set和get方法
}
这些方法可能更常用。实际上,Field类还提供了专门用于基本数据类型的方法,例如setInt()/getInt()、setBoolean()/getBoolean、setChar()/getChar()等等。这里没有列出全部。您可以在需要时查看API文档。应特别注意由final关键字修改的Field字段是安全的,并且可以在运行时接受任何修改,但其实际值最终不会改变。
Method类及其用法
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息,所反映的方法可能是类方法或实例方法(包括抽象方法)。下面是Class类获取Method对象相关的方法:
同样通过案例演示上述方法:
import java.lang.reflect.Method; public class ReflectMethod { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { Class clazz = Class.forName("reflect.Circle"); //根据参数获取public的Method,包含继承自父类的方法
Method method = clazz.getMethod("draw",int.class,String.class); System.out.println("method:"+method); //获取所有public的方法:
Method[] methods =clazz.getMethods();
for (Method m:methods){
System.out.println("m::"+m);
} System.out.println("========================================="); //获取当前类的方法包含private,该方法无法获取继承自父类的method
Method method1 = clazz.getDeclaredMethod("drawCircle");
System.out.println("method1::"+method1);
//获取当前类的所有方法包含private,该方法无法获取继承自父类的method
Method[] methods1=clazz.getDeclaredMethods();
for (Method m:methods1){
System.out.println("m1::"+m);
}
} /**
输出结果:
method:public void reflect.Shape.draw(int,java.lang.String) m::public int reflect.Circle.getAllCount()
m::public void reflect.Shape.draw()
m::public void reflect.Shape.draw(int,java.lang.String)
m::public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
m::public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
m::public final void java.lang.Object.wait() throws java.lang.InterruptedException
m::public boolean java.lang.Object.equals(java.lang.Object)
m::public java.lang.String java.lang.Object.toString()
m::public native int java.lang.Object.hashCode()
m::public final native java.lang.Class java.lang.Object.getClass()
m::public final native void java.lang.Object.notify()
m::public final native void java.lang.Object.notifyAll() =========================================
method1::private void reflect.Circle.drawCircle() m1::public int reflect.Circle.getAllCount()
m1::private void reflect.Circle.drawCircle()
*/
} class Shape {
public void draw(){
System.out.println("draw");
} public void draw(int count , String name){
System.out.println("draw "+ name +",count="+count);
} }
class Circle extends Shape{ private void drawCircle(){
System.out.println("drawCircle");
}
public int getAllCount(){
return 100;
}
}
在上述代码中调用方法,使用了Method类的invoke(Object obj,Object... args)第一个参数代表调用的对象,第二个参数传递的调用方法的参数。这样就完成了类方法的动态调用。
。
Java基础之深入理解Class对象与反射机制的更多相关文章
- Java基础 -- 深入理解Java类型信息(Class对象)与反射机制
一 RTTI概念 认识Claa对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RT ...
- java 基础知识九 类与对象
java 基础知识九 类与对象 1.OO(Object–Oriented )面向对象,OO方法(Object-Oriented Method,面向对象方法,面向对象的方法)是一种把面向对象的思想应 ...
- Java 基础 -- 泛型、集合、IO、反射
package com.java.map.test; import java.util.ArrayList; import java.util.Collection; import java.util ...
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...
- Java基础一篇过(一)反射
一.反射是个啥 定义 : 在运行状态中动态获取的类的信息以及动态调用对象的方法,这种功能称为java语言的反射机制. 对于任意一个类,都能够知道这个类的所有属性和方法. 对于任意一个对象,都能够调用它 ...
- Java匹马行天下之JavaSE核心技术——反射机制
Java反射机制 一.什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及 ...
- xml 转换成对象(采用反射机制对对对象属性赋值)
/// <summary> /// 采用反射机制对对对象属性赋值 /// </summary> /// <param name="node">& ...
- Class对象、反射机制、获取Constructor构造方法
1.Class对象的三种创建方法(Class首字母大写) public class Demo { public static void main(String[] args){ Object obj= ...
- Java注解(Annotation)用法:利用注解和反射机制指定列名导出数据库数据
闲来没事,想了一个应用的例子:用java如何把数据库的数据根据我们指定的某几列,如第2列,第4列,第6列导出来到Excel里? 写代码也是为了应用的,写好的代码更重要的是在于思考.我自己思考了这个示例 ...
随机推荐
- mysql中文进行全文索引支持问题
先来看看对一个字段做全文索引,作为一个数据库系统需要做哪些工作? 假设一个文章表里面包含几个字段:文章id.文章作者.文章标题.文章内容 比如,我们对文章内容这个字段artilce_content建立 ...
- WPF样式继承
场景:样式A和样式B的背景颜色一样,但是文字颜色不一样 <Style x:key="BaseStyle" TargetType="Button"> ...
- [译]Godot系列教程六 - 简单的二维游戏
Pong Godot自带的Demo中有大量更复杂的示例,但这款叫"Pong"的游戏可以对2D游戏的基本特性做一个介绍. 静态资源 本文所用到的一些资源文件:http://files ...
- PowerDesigner使用教程【转】
PowerDesigner使用教程 —— 概念数据模型 一.概念数据模型概述 概念数据模型也称信息模型,它以实体-联系(Entity-RelationShip,简称E-R)理论为基础,并对这 ...
- linux 计划任务(十)
[教程主题]: 计划任务 [1]at 在windows系统中,windows提供了计划任务这一功能,在控制面板 -< 性能与维护 -< 任务计划, 它的功能就是安排自动运行的任务. 通过' ...
- oozie 重新提交作业
在oozie的运行过程当中可能会出现错误,比如数据库连接不上,或者作业执行报错导致流程进入suspend或者killed状态,这个时候我们就要分析了,如果确实是数据或者是网络有问题,我们比如把问题解决 ...
- 创建Maven项目出错
有时候创建maven项目的时候会出错,例如在创建Spring cloud 2 项目的时候,会出现org.apache.maven.archiver.MavenArchiver.getManifest( ...
- APICloud 实践 —— 手机端预览项目
上一次讲到如何创建一个应用,今天讲下如何在手机端预览项目. 1.下载 AppLoader 下载地址:https://docs.apicloud.com/Download/download#apploa ...
- TextView 设置部分文字颜色及点击事件SpannableString
设置TextView中一部分文字的颜色及点击事件. SpannableString gotoMsgListStr = new SpannableString("消息列表"); go ...
- 安卓程序代写 网上程序代写[原]BluetoothClass详解
一. BluetoothClass简介 1. 继承关系 public final class BluetoothClass extends Object implements Parcelable 该 ...