https://blog.csdn.net/mcryeasy/article/details/52344729

https://blog.csdn.net/dufufd/article/details/80537638

Class类简介

  在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RTTI(运行时类型识别,Run-Time Type Identification),多态是基于RTTI实现的。

  每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型 (boolean, byte, char, short, int, long, float, and double)有Class对象,数组有Class对象,就连关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合。

  Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。一个类被加载到内存并供我们使用需要经历如下三个阶段:

  1. 加载,这是由类加载器(ClassLoader)执行的。通过一个类的全限定名来获取其定义的二进制字节流(Class字节码),将这个字节流所代表的静态存储结构转化为方法去的运行时数据接口,根据字节码在java堆中生成一个代表这个类的java.lang.Class对象。

  2. 链接。在链接阶段将验证Class文件中的字节流包含的信息是否符合当前虚拟机的要求,为静态域分配存储空间并设置类变量的初始值(默认的零值),并且如果必需的话,将常量池中的符号引用转化为直接引用。

  3. 初始化。到了此阶段,才真正开始执行类中定义的java程序代码。用于执行该类的静态初始器和静态初始块,如果该类有父类的话,则优先对其父类进行初始化。

  
  所有的类都是在对其第一次使用时,动态加载到JVM中的(懒加载)。当程序创建第一个对类的静态成员的引用时,就会加载这个类。使用new创建类对象的时候也会被当作对类的静态成员的引用。因此java程序程序在它开始运行之前并非被完全加载,其各个类都是在必需时才加载的。这一点与许多传统语言都不同。动态加载使能的行为,在诸如C++这样的静态加载语言中是很难或者根本不可能复制的。

  在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良java代码。一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象。


如何获得Class对象

有三种获得Class对象的方式:

  1. Class.forName(“类的全限定名”)
  2. 实例对象.getClass()
  3. 类名.class (类字面常量)

Class.forName 和getClass()

我们先看看如下的例子:

 
  1. package com.cry;

  2. class Dog {

  3. static {

  4. System.out.println("Loading Dog");

  5. }

  6. }

  7. class Cat {

  8. static {

  9. System.out.println("Loading Cat");

  10. }

  11. }

  12. public class Test {

  13. public static void main(String[] args){

  14. System.out.println("inside main");

  15. new Dog();

  16. System.out.println("after creating Dog");

  17. try {

  18. Class cat=Class.forName("com.cry.Cat");

  19. } catch (ClassNotFoundException e) {

  20. System.out.println("Couldn't find Cat");

  21. }

  22. System.out.println("finish main");

  23. }

  24. }

  25. /* Output:

  26. inside main

  27. Loading Dog

  28. after creating Dog

  29. Loading Cat

  30. finish main

  31. */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

  上面的Dog、Cat类中都有一个静态语句块,该语句块在类第一次被加载时候被执行。这时会有相应的信息打印出来,告诉我们这个类什么时候被加载了。从输出中可以看到,Class对象仅在需要的时候才被加载,static初始化是在类加载时进行的。

  Class.forName方法是Class类的一个静态成员。forName在执行的过程中发现如果类Dog还没有被加载,那么JVM就会调用类加载器去加载Dog类,并返回加载后的Class对象。Class对象和其他对象一样,我们可以获取并操作它的引用。在类加载的过程中,Dog类的静态语句块会被执行。如果Class .forName找不到你要加载的类,它会抛出ClassNotFoundException异常。

  Class.forName的好处就在于,不需要为了获得Class引用而持有该类型的对象,只要通过全限定名就可以返回该类型的一个Class引用。如果你已经有了该类型的对象,那么我们就可以通过调用getClass()方法来获取Class引用了,这个方法属于根类Object的一部分,它返回的是表示该对象的实际类型的Class引用:

 
  1. package com.cry;

  2. class Dog {

  3. static {

  4. System.out.println("Loading Dog");

  5. }

  6. }

  7. public class Test {

  8. public static void main(String[] args) {

  9. System.out.println("inside main");

  10. Dog d = new Dog();

  11. System.out.println("after creating Dog");

  12. Class c = d.getClass();

  13. System.out.println("finish main");

  14. }

  15. }

  16. /* Output:

  17. inside main

  18. Loading Dog

  19. after creating Dog

  20. finish main

  21. */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

利用new操作符创建对象后,类已经装载到内存中了,所以执行getClass()方法的时候,就不会再去执行类加载的操作了,而是直接从java堆中返回该类型的Class引用。

类字面常量

  java还提供了另一种方法来生成对Class对象的引用。即使用类字面常量,就像这样:Cat.class,这样做不仅更简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try语句块中)。并且根除了对forName()方法的调用,所有也更高效。类字面量不仅可以应用于普通的类,也可以应用于接口、数组及基本数据类型。

注意:基本数据类型的Class对象和包装类的Class对象是不一样的:

 
  1. Class c1 = Integer.class;

  2. Class c2 = int.class;

  3. System.out.println(c1);

  4. System.out.println(c2);

  5. System.out.println(c1 == c2);

  6. /* Output

  7. class java.lang.Integer

  8. int

  9. false

  10. */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

但是在包装类中有个一个字段TYPE,TYPE字段是一个引用,指向对应的基本数据类型的Class对象,如下所示,左右两边相互等价: 
 
  
  用.class来创建对Class对象的引用时,不会自动地初始化该Class对象(这点和Class.forName方法不同)。类对象的初始化阶段被延迟到了对静态方法或者非常数静态域首次引用时才执行:

 
  1. package com.cry;

  2. class Dog {

  3. static final String s1 = "Dog_s1";

  4. static String s2 = "Dog_s2";

  5. static {

  6. System.out.println("Loading Dog");

  7. }

  8. }

  9. class Cat {

  10. static String s1 = "Cat_s1";

  11. static {

  12. System.out.println("Loading Cat");

  13. }

  14. }

  15. public class Test {

  16. public static void main(String[] args) throws ClassNotFoundException {

  17. System.out.println("----Star Dog----");

  18. Class dog = Dog.class;

  19. System.out.println("------");

  20. System.out.println(Dog.s1);

  21. System.out.println("------");

  22. System.out.println(Dog.s2);

  23. System.out.println("---start Cat---");

  24. Class cat = Class.forName("com.cry.Cat");

  25. System.out.println("-------");

  26. System.out.println(Cat.s1);

  27. System.out.println("finish main");

  28. }

  29. }

  30. /* Output:

  31. ----Star Dog----

  32. ------

  33. Dog_s1

  34. ------

  35. Loading Dog

  36. Dog_s2

  37. ---start Cat---

  38. Loading Cat

  39. -------

  40. Cat_s1

  41. finish main

  42. */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

  从上面我们可以看到,如果仅使用.class语法来获得对类的Class引用是不会引发初始化的。但是如果使用Class.forName来产生引用,就会立即进行了初始化,就像Cat所看到的。

  如果一个字段被static final修饰,我们称为”编译时常量“,就像Dog的s1字段那样,那么在调用这个字段的时候是不会对Dog类进行初始化的。因为被static和final修饰的字段,在编译期就把结果放入了常量池中了。但是,如果只是将一个域设置为static 或final的,还不足以确保这种行为,就如调用Dog的s2字段后,会强制Dog进行类的初始化,因为s2字段不是一个编译时常量。

通过javap -c -v对Dog的字节码进行反汇编:

 
  1. {

  2. static final java.lang.String s1;

  3. flags: ACC_STATIC, ACC_FINAL

  4. ConstantValue: String Dog_s1

  5. static java.lang.String s2;

  6. flags: ACC_STATIC

  7. com.cry.Dog();

  8. flags:

  9. Code:

  10. stack=1, locals=1, args_size=1

  11. 0: aload_0

  12. 1: invokespecial #1 // Method java/lang/Object."<init>":()V

  13. 4: return

  14. LineNumberTable:

  15. line 3: 0

  16. LocalVariableTable:

  17. Start Length Slot Name Signature

  18. 0 5 0 this Lcom/cry/Dog;

  19. static {};

  20. flags: ACC_STATIC

  21. Code:

  22. stack=2, locals=0, args_size=0

  23. 0: ldc #2 // String Dog_s2

  24. 2: putstatic #3 // Field s2:Ljava/lang/String;

  25. 5: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;

  26. 8: ldc #5 // String Loading Dog

  27. 10: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

  28. 13: return

  29. LineNumberTable:

  30. line 6: 0

  31. line 9: 5

  32. line 10: 13

  33. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

  从上面可以看出s1在编译后被ConstantValue属性修饰 ConstantValue: String Dog_s1,表示即同时被final和static修饰。而s2并没有被ConstantValue修饰,因为它不是一个编译时常量。在static{}中表示类的初始化操作,在操作中我们看到只有s2字段进行了赋值,而却没有s1的踪影,因此调用s1字段是不会触发类的初始化的。

小结

  一旦类被加载了到了内存中,那么不论通过哪种方式获得该类的Class对象,它们返回的都是指向同一个java堆地址上的Class引用。jvm不会创建两个相同类型的Class对象:

 
  1. package com.cry;

  2. class Cat {

  3. static {

  4. System.out.println("Loading Cat");

  5. }

  6. }

  7. public class Test {

  8. public static void main(String[] args) throws ClassNotFoundException {

  9. System.out.println("inside main");

  10. Class c1 = Cat.class;

  11. Class c2= Class.forName("com.cry.Cat");

  12. Class c3=new Cat().getClass();

  13. Class c4 =new Cat().getClass();

  14. System.out.println(c1==c2);

  15. System.out.println(c2==c3);

  16. System.out.println("finish main");

  17. }

  18. }

  19. /* Output:

  20. inside main

  21. -------

  22. Loading Cat

  23. true

  24. true

  25. finish main

  26. */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

从上面我们可以看出执行不同获取Class引用的方法,返回的其实都是同一个Class对象。

  其实对于任意一个Class对象,都需要由它的类加载器和这个类本身一同确定其在就Java虚拟机中的唯一性,也就是说,即使两个Class对象来源于同一个Class文件,只要加载它们的类加载器不同,那这两个Class对象就必定不相等。这里的“相等”包括了代表类的Class对象的equals()、isAssignableFrom()、isInstance()等方法的返回结果,也包括了使用instanceof关键字对对象所属关系的判定结果。所以在java虚拟机中使用双亲委派模型来组织类加载器之间的关系,来保证Class对象的唯一性。


泛型Class引用

  Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。在JavaSE5中,允许你对Class引用所指向的Class对象的类型进行限定,也就是说你可以对Class对象使用泛型语法。通过泛型语法,可以让编译器强制指向额外的类型检查:

 
  1. public final class Class<T> implements java.io.Serializable,

  2. GenericDeclaration,

  3. Type,

  4. AnnotatedElement {

  • 1
  • 2
  • 3
  • 4
 
  1. Class<Integer> c1 = int.class;

  2. c1=Integer.class;

  3. //c1=Double.class; 编译报错

  • 1
  • 2
  • 3

虽然int.class和Integer.class指向的不是同一个Class对象引用,但是它们基本类型和包装类的关系,int可以自动包装为Integer,所以编译器可以编译通过。

泛型中的类型可以持有其子类的引用吗?不行:

Class<Number> c1 = Integer.class;  //编译报错
  • 1

虽然Integer继承自Number,但是编译器无法编译通过。

为了使用泛化的Class引用放松限制,我们还可以使用通配符,它是Java泛型的一部分。通配符的符合是”?“,表示“任何事物“:

 
  1. Class<?> c1 = int.class;

  2. c1= double.class;

  • 1
  • 2

Class

 
  1. Class<? extends Number> c1 = Integer.class;

  2. c1 = Number.class;

  3. c1 = Double.class;

  4. // c1=String.class; 报错,不属于Number类和其子类

  • 1
  • 2
  • 3
  • 4

通配符?不仅可以与extend结合,而且还可以与super关键字相结合,表示被限定为某种类型,或该类型的任何父类型:

 
  1. Class<? super Integer> c1 = Integer.class;

  2. c1 = Number.class;

  3. c1 = Object.class;

  4. c1=Integer.class.getSuperclass();

  • 1
  • 2
  • 3
  • 4

向Class引用添加泛型语法的原因仅仅是为了提供编译期类型检查。


Class类的方法

方法名 说明
forName() (1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。
(2)为了产生Class引用,forName()立即就进行了初始化。
Object-getClass() 获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。
getName() 取全限定的类名(包括包名),即类的完整名字。
getSimpleName() 获取类名(不包括包名)
getCanonicalName() 获取全限定的类名(包括包名)
isInterface() 判断Class对象是否是表示一个接口
getInterfaces() 返回Class对象数组,表示Class对象所引用的类所实现的所有接口。
getSupercalss() 返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现一个对象完整的继承结构。
newInstance() 返回一个Oject对象,是实现“虚拟构造器”的一种途径。使用该方法创建的类,必须带有无参的构造器。
getFields() 获得某个类的所有的公共(public)的字段,包括继承自父类的所有公共字段。 类似的还有getMethods和getConstructors。
getDeclaredFields 获得某个类的自己声明的字段,即包括public、private和proteced,默认但是不包括父类声明的任何字段。类似的还有getDeclaredMethods和getDeclaredConstructors。

 
  1. package com.cry;

  2. import java.lang.reflect.Field;

  3. interface I1 {

  4. }

  5. interface I2 {

  6. }

  7. class Cell{

  8. public int mCellPublic;

  9. }

  10. class Animal extends Cell{

  11. private int mAnimalPrivate;

  12. protected int mAnimalProtected;

  13. int mAnimalDefault;

  14. public int mAnimalPublic;

  15. private static int sAnimalPrivate;

  16. protected static int sAnimalProtected;

  17. static int sAnimalDefault;

  18. public static int sAnimalPublic;

  19. }

  20. class Dog extends Animal implements I1, I2 {

  21. private int mDogPrivate;

  22. public int mDogPublic;

  23. protected int mDogProtected;

  24. private int mDogDefault;

  25. private static int sDogPrivate;

  26. protected static int sDogProtected;

  27. static int sDogDefault;

  28. public static int sDogPublic;

  29. }

  30. public class Test {

  31. public static void main(String[] args) throws IllegalAccessException, InstantiationException {

  32. Class<Dog> dog = Dog.class;

  33. //类名打印

  34. System.out.println(dog.getName()); //com.cry.Dog

  35. System.out.println(dog.getSimpleName()); //Dog

  36. System.out.println(dog.getCanonicalName());//com.cry.Dog

  37. //接口

  38. System.out.println(dog.isInterface()); //false

  39. for (Class iI : dog.getInterfaces()) {

  40. System.out.println(iI);

  41. }

  42. /*

  43. interface com.cry.I1

  44. interface com.cry.I2

  45. */

  46. //父类

  47. System.out.println(dog.getSuperclass());//class com.cry.Animal

  48. //创建对象

  49. Dog d = dog.newInstance();

  50. //字段

  51. for (Field f : dog.getFields()) {

  52. System.out.println(f.getName());

  53. }

  54. /*

  55. mDogPublic

  56. sDogPublic

  57. mAnimalPublic

  58. sAnimalPublic

  59. mCellPublic //父类的父类的公共字段也打印出来了

  60. */

  61. System.out.println("---------");

  62. for (Field f : dog.getDeclaredFields()) {

  63. System.out.println(f.getName());

  64. }

  65. /** 只有自己类声明的字段

  66. mDogPrivate

  67. mDogPublic

  68. mDogProtected

  69. mDogDefault

  70. sDogPrivate

  71. sDogProtected

  72. sDogDefault

  73. sDogPublic

  74. */

  75. }

  76. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

getName、getCanonicalName与getSimpleName的区别:

getSimpleName:只获取类名 
getName:类的全限定名,jvm中Class的表示,可以用于动态加载Class对象,例如Class.forName。 
getCanonicalName:返回更容易理解的表示,主要用于输出(toString)或log打印,大多数情况下和getName一样,但是在内部类、数组等类型的表示形式就不同了。

 
  1. package com.cry;

  2. public class Test {

  3. private class inner{

  4. }

  5. public static void main(String[] args) throws ClassNotFoundException {

  6. //普通类

  7. System.out.println(Test.class.getSimpleName()); //Test

  8. System.out.println(Test.class.getName()); //com.cry.Test

  9. System.out.println(Test.class.getCanonicalName()); //com.cry.Test

  10. //内部类

  11. System.out.println(inner.class.getSimpleName()); //inner

  12. System.out.println(inner.class.getName()); //com.cry.Test$inner

  13. System.out.println(inner.class.getCanonicalName()); //com.cry.Test.inner

  14. //数组

  15. System.out.println(args.getClass().getSimpleName()); //String[]

  16. System.out.println(args.getClass().getName()); //[Ljava.lang.String;

  17. System.out.println(args.getClass().getCanonicalName()); //java.lang.String[]

  18. //我们不能用getCanonicalName去加载类对象,必须用getName

  19. //Class.forName(inner.class.getCanonicalName()); 报错

  20. Class.forName(inner.class.getName());

  21. }

  22. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

参考:

https://blog.csdn.net/mcryeasy/article/details/52344729
java中的Class对象和new关键字解析 
Thinking in Java

java中class对象的理解 讲得相当不错 很接地气 引用下相关推荐

  1. 高薪程序员面试题精讲系列15之Java中的对象如何实现排序?

    一. 面试题及剖析 1. 今日面试题 我们在项目开发时,有时候会遇到列表搜索查询等效果,其中大部分都可以利用SQL语句来实现,但也有些特殊的搜索排序利用SQL是很难实现的,比如对中文进行排序.说到排序 ...

  2. 【性能优化】面试官:Java中的对象和数组都是在堆上分配的吗?

    写在前面 从开始学习Java的时候,我们就接触了这样一种观点:Java中的对象是在堆上创建的,对象的引用是放在栈里的,那这个观点就真的是正确的吗?如果是正确的,那么,面试官为啥会问:"Jav ...

  3. Java中,一切皆是对象——java中的对象类型与基本数据类型的区别

    起因:取一个list给另一个list赋值,然后在另一个list中取出进行修改.list其中类型为对象时,String时,基本数据类型时. [java中的对象类型与基本数据类型的区别] #声明和实例化 ...

  4. java中String对象作为参数传递问题

    问题 java中将对象作为参数传递究竟是值传递还是引用传递? 1.基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的. 2.对象作为参数传递时,是把对象在内存中的地址拷贝 ...

  5. 深圳Java培训:Java中的对象流和序列化

    深圳Java培训:Java中的对象流和序列化 最近,在讲流的使用,其中对象流的作用其实就是将自定义类的对象与流之间相互转换的流. 看起来还是挺简单的,那么看下面的例子: public class St ...

  6. Java中Map集合如何理解(四)——精简

    目录 引言 概念 Map集合实现类 HashMap LinkedHashMap TreeMap 默认排序 自定义排序方式 常用API 遍历Map集合 键找值 键值对 Lambda表达式 结束语 引言 ...

  7. Java中的反射机制详讲

    Java中的反射机制详讲 1.反射机制_介绍_Class对象获取 2.反射机制_动态操作_构造器_方法_属性 3.动态编译_DanamicCompile_反射调用main方法问题 好文推荐:排序.查找 ...

  8. java中实现对象的深度克隆

    1.什么是深度拷贝和浅拷贝 python中有深度拷贝(也可以叫深度克隆)和浅拷贝,同样在java中很多时候需要深度拷贝对象,所谓的深度拷贝对象指的就是对于对象的所用数据及其全部进行copy一份,变成两 ...

  9. java中String对象和String变量

    2019独角兽企业重金招聘Python工程师标准>>> java中String对象和String变量 (2011-12-27 20:40:27) 转载▼ 标签: it 最近在论坛上看 ...

最新文章

  1. void addColumn(TableColumn aColumn)
  2. 洛谷 P4245 【模板】MTT
  3. 【LeetCode】LeetCode之跳跃游戏——动态规划+贪心算法
  4. JS trim的实现
  5. MySQL服务器意外关机-无法启动多实例
  6. 2018中国十大科技进展公布!两院院士投票,港珠澳大桥和天河三号上榜
  7. python3入门代码-Python3入门(十三)——连接数据库
  8. UI设计和平面设计有什么区别哪个前景更好
  9. Tomcat安装配置(详细步骤)
  10. cc2500的register操作
  11. 后台事务自动跳转工作流节点
  12. vue结合vue-amap调用高德地图行政区划分并添加标记点
  13. excel表格自动添加边框
  14. 苹果html向上滑动不流畅,苹果手机Safari浏览器下滑动卡顿的问题
  15. C++ + win32 + STL 写的QQ连连看外挂
  16. NVMe | 热插拔
  17. win下apache2.4 支持php8.0
  18. 自动识别查找特定的串口号 比如设备管理器中Modem属性里的串口 按这个方法可以获取设备管理器任意信息。C++
  19. 计算机怎么解除c盘用户权限,电脑c盘文件夹拒绝访问怎么办 删除c盘文件如何获得管理员权限...
  20. 【Day06_0423】C语言选择题

热门文章

  1. find name 模糊匹配_Linux的文件搜索命令(locate ,find,grep,find命令和)
  2. python编写测试工具-python 写一个性能测试工具(一)
  3. mysql数据库空闲时间设定_关于数据库连接池的最大空闲时间的配置
  4. php匹配ubb,将php实现过滤UBB代码
  5. php5.3安装memcache,Windows下的Memcache安装 附php5.3的扩展
  6. vscode快速注释_Python快速入门(一)
  7. linux efi启动,可启动USB Linux的EFI/ UEFI
  8. 20145328 《网络对抗技术》恶意代码分析
  9. 【noi 2.5_7834】分成互质组(dfs)
  10. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端