class_classloader - CSDN
class 订阅
CLASS是一种在网络工程中的一种协议。一般组词为“CLASSLESS”(无类)或者“CLASSFUL”(有类)。面向对象编程中一个无明显特点的范畴,用于描述一组更具体的称为对象的东西。另有日本乐队组合名称也为CLASS。同时,class也是C++语言中的关键字,在matlab中class用于获取变量的类型。 展开全文
CLASS是一种在网络工程中的一种协议。一般组词为“CLASSLESS”(无类)或者“CLASSFUL”(有类)。面向对象编程中一个无明显特点的范畴,用于描述一组更具体的称为对象的东西。另有日本乐队组合名称也为CLASS。同时,class也是C++语言中的关键字,在matlab中class用于获取变量的类型。
信息
外文名
CLASS
一般组词
CLASSLESS CLASSFUL
释    义
网络工程中的一种协议
所属学科
网络工程
CLASS简介
CLASS是在网工中经常与协议相连。一个类为定义一种特定对象的行为提供了模板(扩展名).java文件被编译后生成.class文件。
收起全文
精华内容
参与话题
  • Class的基本用法

    千次阅读 2018-07-23 10:23:40
    Class(类)这个概念,作为对象的模板。class可以看作只是一个语法糖,通过class关键字,可以定义类。让对象原型的写法更加清晰、更像面向对象编程的语法。类和模块的内部,默认就是严格模式,所以不需要使用use ...

    Class(类)这个概念,作为对象的模板。class可以看作只是一个语法糖,通过class关键字,可以定义类。让对象原型的写法更加清晰、更像面向对象编程的语法。类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。

    1.constructor方法和实例对象

    //定义类
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }

    ES6 的类,完全可以看作构造函数的另一种写法。类的数据类型就是函数,类本身就指向构造函数。使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。类必须使用new调用,否则会报错。

    class Point {
      // ...
    }
    
    typeof Point // "function"
    Point === Point.prototype.constructor // true   prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
    
    class Bar {
      doStuff() {
        console.log('stuff');
      }
    }
    
    var b = new Bar();
    b.doStuff() // "stuff"

    类的所有方法都定义在类的prototype属性上面。在类的实例上面调用方法,其实就是调用原型prototype对象上的方法,所以类的新方法可以添加在prototype对象上面。Object.assign方法可以很方便地一次向类添加多个方法。

    class Point {
      constructor() {
      }
    
      toValue() {
      }
    }
    
    // 等同于
    
    Point.prototype = {
      constructor() {},
      toValue() {},
    };
    
    
    Object.assign(Point.prototype, {
      toString(){},
    });

    类的内部所有定义的方法,都是不可枚举的。

    class Point {
      constructor(x, y) {
      }
    
      toString() {
      }
    }
    
    Object.keys(Point.prototype)// []
    Object.getOwnPropertyNames(Point.prototype)// ["constructor","toString"]
    
    
    var Point = function (x, y) {
    };
    
    Point.prototype.toString = function() {
    };
    
    Object.keys(Point.prototype)// ["toString"]
    Object.getOwnPropertyNames(Point.prototype)// ["constructor","toString"]

    类的属性名,可以采用表达式。constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。

    let methodName = 'getArea';
    
    class Square {
      constructor(length) {
      }
    
      [methodName]() {
      }
    }
    class Point {
    }
    
    // 等同于
    class Point {
      constructor() {}
    }
    
    class Foo {
      constructor() {
        return Object.create(null);
      }
    }
    
    new Foo() instanceof Foo
    // false   constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例。

    与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。此外,类的所有实例共享一个原型对象,这也意味着,可以通过实例的__proto__属性为“类”添加方法。

    //定义类
    class Point {
    
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    
    }
    
    var point = new Point(2, 3);
    
    point.toString() // (2, 3)
    
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    point.hasOwnProperty('toString') // false
    point.__proto__.hasOwnProperty('toString') // true
    
    
    var p1 = new Point(2,3);
    var p2 = new Point(3,2);
    
    p1.__proto__ === p2.__proto__//true
    //__proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,虽然目很多浏览器的 JS 引擎中都提供了这个私有属性,但不建议在生产中使用该属性,避免对环境产生依赖。生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。
    var p1 = new Point(2,3);
    var p2 = new Point(3,2);
    
    p1.__proto__.printName = function () { return 'Oops' };
    
    p1.printName() // "Oops"
    p2.printName() // "Oops"
    
    var p3 = new Point(4,2);
    p3.printName() // "Oops"
    
    //在p1的原型上添加了一个printName方法,由于p1的原型就是p2的原型,因此p2也可以调用这个方法。而且,此后新建的实例p3也可以调用这个方法。这意味着,使用实例的__proto__属性改写原型,必须相当谨慎,因为这会改变“类”的原始定义,影响到所有实例。

    2.Class表达式:与函数一样,类也可以使用表达式的形式定义。

    //这个类的名字是MyClass而不是Me,Me只在 Class 的内部代码可用,指代当前类。如果类的内部没用到的话,可以省略Me。
    const MyClass = class Me {
      getClassName() {
        return Me.name;
      }
    };
    
    let inst = new MyClass();
    inst.getClassName() // Me
    Me.name // ReferenceError: Me is not defined

    采用 Class 表达式,可以写出立即执行的 Class。

    let person = new class {
      constructor(name) {
        this.name = name;
      }
    
      sayName() {
        console.log(this.name);
      }
    }('张三');
    
    person.sayName(); // "张三"

    3.不存在变量提升:

    new Foo(); // ReferenceError  Foo类使用在前,定义在后,这样会报错,因为 ES6 不会把类的声明提升到代码头部。
    class Foo {}
    
    {
      let Foo = class {};
      class Bar extends Foo {
      }
    } //因为Bar继承Foo的时候,Foo已经有定义了。
    

    4.私有方法和私有属性

    //1.在命名上加以区别
    class Widget {
    
      // 公有方法
      foo (baz) {
        this._bar(baz);
      }
    
      // 私有方法
      _bar(baz) {//表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法。
    
    
        return this.snaf = baz;
      }
    
      // ...
    }
    
    //2.将私有方法移出模块
    class Widget {
      foo (baz) {
        bar.call(this, baz);
      }
    
      // ...
    }
    
    function bar(baz) {
      return this.snaf = baz;
    }
    
    //3.利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
    const bar = Symbol('bar');
    const snaf = Symbol('snaf');
    
    export default class myClass{
    
      // 公有方法
      foo(baz) {
        this[bar](baz);
      }
    
      // 私有方法
      [bar](baz) {
        return this[snaf] = baz;
      }
    
      // ...
    };
    
    //新的前缀#表示私有属性,而没有采用private关键字,是因为 JavaScript 是一门动态语言,使用独立的符号似乎是唯一的可靠方法,能够准确地区分一种属性是否为私有属性。
    
    class Foo {
      #a;
      #b;
      #sum() { return #a + #b; }
      printSum() { console.log(#sum()); }
      constructor(a, b) { #a = a; #b = b; }
    }

    5.this的指向:类的方法内部如果含有this,它默认指向类的实例。

    class Logger {
      printName(name = 'there') {
        this.print(`Hello ${name}`);
      }
    
      print(text) {
        console.log(text);
      }
    }
    
    const logger = new Logger();
    const { printName } = logger;
    printName(); // TypeError: Cannot read property 'print' of undefined 
    //printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。

    解决this找不到的方法:1)构造方法中绑定this  2)使用箭头函数   3)使用Proxy,获取方法的时候,自动绑定this。

    class Logger {
      constructor() {
        this.printName = this.printName.bind(this);
      }
    }
    
    class Logger {
      constructor() {
        this.printName = (name = 'there') => {
          this.print(`Hello ${name}`);
        };
      }
    }
    
    function selfish (target) {
      const cache = new WeakMap();
      const handler = {
        get (target, key) {
          const value = Reflect.get(target, key);
          if (typeof value !== 'function') {
            return value;
          }
          if (!cache.has(value)) {
            cache.set(value, value.bind(target));
          }
          return cache.get(value);
        }
      };
      const proxy = new Proxy(target, handler);
      return proxy;
    }
    
    const logger = selfish(new Logger());

    6.class的取值函数getter和取值函数setter,存值函数和取值函数是设置在属性的 Descriptor描述 对象上的。

    class MyClass {
      constructor() {
        // ...
      }
      get prop() {
        return 'getter';
      }
      set prop(value) {
        console.log('setter: '+value);
      }
    }
    
    let inst = new MyClass();
    
    inst.prop = 123;
    // setter: 123
    
    inst.prop
    // 'getter'

    7.class的静态方法:类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

    class Foo {
      static classMethod() {
        return 'hello';
      }
    }
    
    Foo.classMethod() // 'hello'
    
    var foo = new Foo();
    foo.classMethod()// TypeError: foo.classMethod is not a function
    
    
    //如果静态方法包含this关键字,这个this指的是类,而不是实例。静态方法可以与非静态方法重名。
    class Foo {
      static bar () {
        this.baz();
      }
      static baz () {
        console.log('hello');
      }
      baz () {
        console.log('world');
      }
    }
    
    Foo.bar() // hello   静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。

    父类的静态方法,可以被子类继承,可以从super对象上调用。

    class Foo {
      static classMethod() {
        return 'hello';
      }
    }
    
    class Bar extends Foo {
      static classMethod() {
        return super.classMethod() + ', too';
      }
    }
    Bar.classMethod() // "hello, too"
    

    8.class的静态属性和实例属性(Class 内部只有静态方法,没有静态属性)

    (1)类的实例属性:类的实例属性可以用等式,写入类的定义之中。

    class MyClass {
      myProp = 42;
    
      constructor() {
        console.log(this.myProp); // 42
      }
    }
    

    为了可读性的目的,对于那些在constructor里面已经定义的实例属性,新写法允许直接列出。

    class ReactCounter extends React.Component {
      state = {
        count: 0
      };
    }

    (2)类的静态属性:类的静态属性只要在上面的实例属性写法前面,加上static关键字就可以了。

    class MyClass {
      static myStaticProp = 42;
    
      constructor() {
        console.log(MyClass.myStaticProp); // 42
      }
    }

    9.new.target属性:

    new是从构造函数生成实例对象的命令。new.target属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

    function Person(name) {
      if (new.target !== undefined) {//new.target === Person
        this.name = name;
      } else {
        throw new Error('必须使用 new 命令生成实例');
      }
    }
    
    
    var person = new Person('张三'); // 正确
    var notAPerson = Person.call(person, '张三');  // 报错

    Class 内部调用new.target,返回当前 Class。子类继承父类时,new.target会返回子类。利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。

    class Rectangle {
      constructor(length, width) {
        console.log(new.target === Rectangle);
        this.length = length;
        this.width = width;
      }
    }
    
    var obj = new Rectangle(3, 4); // 输出 true
    
    class Square extends Rectangle {
      constructor(length) {
        super(length, length);
      }
    }
    
    var obj1 = new Square(3); // 输出 false
    class Shape {
      constructor() {
        if (new.target === Shape) {
          throw new Error('本类不能实例化');
        }
      }
    }
    
    class Rectangle extends Shape {
      constructor(length, width) {
        super();
        // ...
      }
    }
    
    var x = new Shape();  // 报错 Uncaught Error: 本类不能实例化
    var y = new Rectangle(3, 4);  // 正确  Shape类不能被实例化,只能用于继承。注意,在函数外部,使用new.target会报错。

     

    展开全文
  • Class类简介

    千次阅读 2018-05-25 19:39:41
    1、Class类简介:  Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型...

    1、Class类简介:


     Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
          Class 没有公共构造方法。Class 对象是在加载类时由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。 
          虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
          基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 
          每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
          一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

    一、如何得到Class的对象呢?有三种方法可以的获取:

      1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
        MyObject x;
        Class c1 = x.getClass();

     2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如: 
        Class c2=Class.forName(“MyObject”),Employee必须是接口或者类的名字。

    3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
        Class cl1 = Manager.class;
        Class cl2 = int.class;
        Class cl3 = Double[].class;
        注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。

    二、Class类的常用方法

    1、getName() 

    一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

    2、newInstance()

    Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance()。例如:
        x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。

    3、getClassLoader() 

    返回该类的类加载器。

       4、getComponentType() 
        返回表示数组组件类型的 Class。

       5、getSuperclass() 
        返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

       6、isArray() 
        判定此 Class 对象是否表示一个数组类。

    三、Class的一些使用技巧

    1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如
        Object obj = Class.forName(s).newInstance();

    2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:
        if(e.getClass() == Employee.class)…

    2、 Class.forName()方法:


    Class.forName返回与给定的字符串名称相关联接口的Class对象。

    Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。第一种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。

    static Class<?>

    forName(String className)

    Returns the Class object associated with the class or interface with the given string name.

    static Class<?>

    forName(String name, boolean initialize, ClassLoader loader)

    Returns the Class object associated with the class or interface with the given string name, using the given class loader.

    说明:

    publicstatic Class<?> forName(String className)

    Returns the Class object associated withthe class or interface with the given string name. Invokingthis method is equivalent to:

    Class.forName(className,true, currentLoader)

    where currentLoader denotes the definingclass loader of the current class.

    For example, thefollowing code fragment returns the runtime Class descriptor for theclass named java.lang.Thread:

    Class t =Class.forName("java.lang.Thread")

    A call to forName("X") causes theclass named X to beinitialized.

    Parameters:

    className - the fully qualifiedname of the desired class.

    Returns:

    the Class object for the classwith the specified name.

    从官方给出的API文档中可以看出:

    Class.forName(className)实际上是调用Class.forName(className,true, this.getClass().getClassLoader())。第二个参数,是指Class被loading后是不是必须被初始化。可以看出,使用Class.forName(className)加载类时则已初始化。

    所以Class.forName(className)可以简单的理解为:获得字符串参数中指定的类,并初始化该类

     

     一.首先你要明白在java里面任何class都要装载在虚拟机上才能运行。

    1.      forName这句话就是装载类用的(new是根据加载到内存中的类创建一个实例,要分清楚)。 

    2.      至于什么时候用,可以考虑一下这个问题,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?

               A a = (A)Class.forName(“pacage.A”).newInstance();这和 A a =new A();是一样的效果。

    3.      jvm在装载类时会执行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再执行这段静态代码了。

    4.      Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

    5.      动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象

           String str = 用户输入的字符串  

           Class t = Class.forName(str);  

           t.newInstance(); 

     二.在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

          1.它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

          2.那么为什么会有两种创建对象方式?

            这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。  
            Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。例如:

               class c = Class.forName(“Example”);  

               factory = (ExampleInterface)c.newInstance();  

           其中ExampleInterface是Example的接口,可以写成如下形式:

              String className = “Example”;  

              class c = Class.forName(className);  

              factory = (ExampleInterface)c.newInstance();  

          进一步可以写成如下形式:

              String className = readfromXMlConfig;//从xml 配置文件中获得字符串

             class c = Class.forName(className);  

             factory = (ExampleInterface)c.newInstance();  

            上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。  
            3.从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。  但是使用newInstance()方法的时候,

             就必须保证:

                  1、这个类已经加载;

                  2、这个类已经连接了。

            而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。  
             现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好

             的灵活性,提供给了一种降耦的手段。  

    三.最后用最简单的描述来区分new关键字和newInstance()方法的区别: 

    1. newInstance: 弱类型。低效率。只能调用无参构造。  
             2. new: 强类型。相对高效。能调用任何public构造。

    3、应用情景:


    情景一:加载数据库驱动的时候

    Class.forName的一个很常见的用法是在加载数据库驱动的时候。

    如:

    1. Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);  
    2. Connection con=DriverManager.getConnection(”jdbc:sqlserver://localhost:1433;DatabaseName==JSP”,“jph”,“jph”);      
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");    

      为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?

    即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢? 

    刚才提到,Class.forName(“”);的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。

    而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBCDriver的Driver类的代码都必须类似如下: 
              public classMyJDBCDriver implements Driver {

        static{

           DriverManager.registerDriver(new MyJDBCDriver());

       }

       } 

      既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

    情景二:使用AIDL与电话管理Servic进行通信

    Method method =Class.forName(“android.os.ServiceManager”)

             .getMethod(“getService”,String.class);

    // 获取远程TELEPHONY_SERVICEIBinder对象的代理

    IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});

    // IBinder对象的代理转换为ITelephony对象

    ITelephonytelephony = ITelephony.Stub.asInterface(binder);

    // 挂断电话

    telephony.endCall();


    参考资料:


    JDK1.8_API…/docs/api/java/lang/Class.html

    http://www.ibm.com/developerworks/cn/java/j-lo-classloader/

    展开全文
  • python中class的定义及使用

    万次阅读 多人点赞 2019-06-08 21:25:32
    #类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。 #对象:它是类的实例化。 #方法:类中定义的函数。 #类(Class) 由3个部分构成: ''' 类的名称:类名 类的属性...
    #类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。
    #对象:它是类的实例化。
    #方法:类中定义的函数。
    
    #类(Class) 由3个部分构成:
    '''
    类的名称:类名
    类的属性:指对象的特征(一组数据)
    类的方法:允许对象进行操作的方法 (行为/功能)
    '''
    
    # Python 3.x中取消了经典类,默认都是新式类。
    # 新式类的语法 -> class 类名(object): pass
    
    # 类对象支持两种操作:属性引用 和 实例化。
    # 属性引用的语法:obj.属性
    # 类实例化的语法:obj = 类名()
    # 类中方法的调用:obj.方法名()
    
    
    # 下面分析新式类的2种常见形式:
    
    #例1:
    #自定义一个类student
    class student(object):
        def speak(self):  ## 哪个对象调用了这个方法,self就是那个对象;可以把self理解为一个形参
            print("%s 说:我今年%s岁" % (self.name, self.age))
    
    #类student 实例化一个对象john
    john = student()
    # 给对象添加属性
    john.name = "约翰"
    john.age = 19
    # 调用类中的 speak()方法
    john.speak()
    #<<<约翰 说:我今年19岁
    
    
    #例2:
    class student(object):
        # 定义构造方法
        def __init__(self, n, a):  #__init__() 是类的初始化方法;它在类的实例化操作后 会自动调用,不需要手动调用;
            # 设置属性
            self.name = n
            self.age = a
        # 定义普通方法
        def speak(self):
            print("%s 说:我今年%s岁" % (self.name, self.age))
    
    #类student 实例化一个对象john
    john = student("约翰",19)
    
    # 调用类中的 speak()方法
    john.speak()
    #>>>约翰 说:我今年19岁
    
    # 在python中使用__开头 并以__结尾的方法,称之为魔法方法;
    # __init__(self) 是类的初始化方法,也称构造方法,是一种特殊的魔法方法。
    # __init__(self)在实例化后,会自动调用,而不用手动调用,所以一般把属性设置在_init__()里。
    # 常用到的魔法方法还有:__str__(self) 、 __del__(self)等。
    
    ## __str__(self)
    class student(object):
        # 定义构造方法
        def __init__(self, n, a):
            # 设置属性
            self.name = n
            self.age = a
            
        # 输出一个字符串(追踪对象属性信息变化)
        def __str__(self):  # __str__(self)不可以添加参数(形参)
            return "名字:%s 年龄:%d" % (self.name, self.age)
    
    # 实例化一个对象john
    john = student("约翰",19)
    
    # 当使用print输出对象时,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
    print(john)
    #>>>名字:约翰 年龄:19
    
    

     

    展开全文
  • class文件 某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行...

    什么是类?可以理解为。class文件

    某种意义上来说,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)

     System.out.println(int.class.getName());
            System.out.println(char.class.getName());
            System.out.println(short.class.getName());
            System.out.println(long.class.getName());
            System.out.println(byte.class.getName());
            System.out.println(float.class.getName());
            System.out.println(double.class.getName());
            System.out.println(boolean.class.getName());
            System.out.println(void.class.getName());
     System.out.println(char[].class.getName());//[C
            System.out.println(char[][].class.getName());//[[C

     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()

    我们先看看如下的例子:

    package com.cry;
    class Dog {
        static {
            System.out.println("Loading Dog");
        }
    }
    class Cat {
        static {
            System.out.println("Loading Cat");
        }
    }
    public class Test {
        public static void main(String[] args){
            System.out.println("inside main");
            new Dog();
            System.out.println("after creating Dog");
            try {
                Class cat=Class.forName("com.cry.Cat");
            } catch (ClassNotFoundException e) {
                System.out.println("Couldn't find Cat");
            }
            System.out.println("finish main");
        }
    }
    /* Output:
        inside main
        Loading Dog
        after creating Dog
        Loading Cat
        finish main
     */

    上面的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引用:

    class Dog {
        static {
            System.out.println("Loading Dog");
        }
    }
    public class Test {
        public static void main(String[] args) {
            System.out.println("inside main");
            Dog d = new Dog();
            System.out.println("after creating Dog");
            Class c = d.getClass();
            System.out.println("finish main");
        }
    }
    /* Output:
        inside main
        Loading Dog
        after creating Dog
        finish main
     */

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

    类字面常量

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

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

    Class c1 = Integer.class;
    Class c2 = int.class;
    System.out.println(c1);
    System.out.println(c2);
    System.out.println(c1 == c2);
    /* Output
    class java.lang.Integer
    int
    false
    */

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

    class Dog {
        static final String s1 = "Dog_s1";
        static  String s2 = "Dog_s2";
        static {
            System.out.println("Loading Dog");
        }
    }
    class Cat {
        static String s1 = "Cat_s1";
        static {
            System.out.println("Loading Cat");
        }
    }
    public class Test {
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.println("----Star Dog----");
            Class dog = Dog.class;
            System.out.println("------");
            System.out.println(Dog.s1);
            System.out.println("------");
            System.out.println(Dog.s2);
            System.out.println("---start Cat---");
            Class cat = Class.forName("com.cry.Cat");
            System.out.println("-------");
            System.out.println(Cat.s1);
            System.out.println("finish main");
        }
    }
    /* Output:
    ----Star Dog----
    ------
    Dog_s1
    ------
    Loading Dog
    Dog_s2
    ---start Cat---
    Loading Cat
    -------
    Cat_s1
    finish main
     */

     

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

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

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

    {
      static final java.lang.String s1;
        flags: ACC_STATIC, ACC_FINAL
        ConstantValue: String Dog_s1
      static java.lang.String s2;
        flags: ACC_STATIC
      com.cry.Dog();
        flags:
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 3: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   0       5     0  this   Lcom/cry/Dog;
      static {};
        flags: ACC_STATIC
        Code:
          stack=2, locals=0, args_size=0
             0: ldc           #2                  // String Dog_s2
             2: putstatic     #3                  // Field s2:Ljava/lang/String;
             5: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
             8: ldc           #5                  // String Loading Dog
            10: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            13: return
          LineNumberTable:
            line 6: 0
            line 9: 5
            line 10: 13
    }

     

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

    小结

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

    package com.cry;
    class Cat {
        static {
            System.out.println("Loading Cat");
        }
    }
    public class Test {
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.println("inside main");
            Class c1 = Cat.class;
            Class c2= Class.forName("com.cry.Cat");
            Class c3=new Cat().getClass();
            Class c4 =new Cat().getClass();
            System.out.println(c1==c2);
            System.out.println(c2==c3);
            System.out.println("finish main");
        }
    }
    /* Output:
    inside main
    -------
    Loading Cat
    true
    true
    finish main
     */

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

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


    泛型Class引用

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

        public final class Class<T> implements java.io.Serializable,
                                      GenericDeclaration,
                                      Type,
                                      AnnotatedElement {
       Class<Integer> c1 = int.class;
       c1=Integer.class;
       //c1=Double.class; 编译报错

     

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

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

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

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

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

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

    Class

            Class<? extends Number> c1 = Integer.class;
            c1 = Number.class;
            c1 = Double.class;
            // c1=String.class; 报错,不属于Number类和其子类

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

            Class<? super Integer> c1 = Integer.class;
            c1 = Number.class;
            c1 = Object.class;
            c1=Integer.class.getSuperclass();

    向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。

    
     
    import java.lang.reflect.Field;
    interface I1 {
    }
    interface I2 {
    }
    class Cell{
        public int mCellPublic;
    }
    class Animal extends  Cell{
        private int mAnimalPrivate;
        protected int mAnimalProtected;
        int mAnimalDefault;
        public int mAnimalPublic;
        private static int sAnimalPrivate;
        protected static int sAnimalProtected;
        static int sAnimalDefault;
        public static int sAnimalPublic;
    }
    class Dog extends Animal implements I1, I2 {
        private int mDogPrivate;
        public int mDogPublic;
        protected int mDogProtected;
        private int mDogDefault;
        private static int sDogPrivate;
        protected static int sDogProtected;
        static int sDogDefault;
        public static int sDogPublic;
    }
    public class Test {
        public static void main(String[] args) throws IllegalAccessException, InstantiationException {
            Class<Dog> dog = Dog.class;
            //类名打印
            System.out.println(dog.getName()); //com.cry.Dog
            System.out.println(dog.getSimpleName()); //Dog
            System.out.println(dog.getCanonicalName());//com.cry.Dog
            //接口
            System.out.println(dog.isInterface()); //false
            for (Class iI : dog.getInterfaces()) {
                System.out.println(iI);
            }
             /*
              interface com.cry.I1
              interface com.cry.I2
             */
     
            //父类
            System.out.println(dog.getSuperclass());//class com.cry.Animal
            //创建对象
            Dog d = dog.newInstance();
            //字段
            for (Field f : dog.getFields()) {
                System.out.println(f.getName());
            }
            /*
                mDogPublic
                sDogPublic
                mAnimalPublic
                sAnimalPublic
                mCellPublic  //父类的父类的公共字段也打印出来了
             */
            System.out.println("---------");
            for (Field f : dog.getDeclaredFields()) {
                System.out.println(f.getName());
            }
            /** 只有自己类声明的字段
             mDogPrivate
             mDogPublic
             mDogProtected
             mDogDefault
             sDogPrivate
             sDogProtected
             sDogDefault
             sDogPublic
             */
        }
    }

     

    getName、getCanonicalName与getSimpleName的区别:

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

    public class Test {
        private  class inner{
        }
        public static void main(String[] args) throws ClassNotFoundException {
            //普通类
            System.out.println(Test.class.getSimpleName()); //Test
            System.out.println(Test.class.getName()); //com.cry.Test
            System.out.println(Test.class.getCanonicalName()); //com.cry.Test
            //内部类
            System.out.println(inner.class.getSimpleName()); //inner
            System.out.println(inner.class.getName()); //com.cry.Test$inner
            System.out.println(inner.class.getCanonicalName()); //com.cry.Test.inner
            //数组
            System.out.println(args.getClass().getSimpleName()); //String[]
            System.out.println(args.getClass().getName()); //[Ljava.lang.String;
            System.out.println(args.getClass().getCanonicalName()); //java.lang.String[]
            //我们不能用getCanonicalName去加载类对象,必须用getName
            //Class.forName(inner.class.getCanonicalName()); 报错
            Class.forName(inner.class.getName());
        }
    }

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

    展开全文
  • C++类(Class)的定义与实现

    万次阅读 多人点赞 2018-08-01 17:41:17
    一、"类" 的介绍  在C++中, 用 "类" 来描述 "对象", 所谓的"对象"是指现实世界中的一切事物。那么类就可以看做是对相似事物的抽象, 找到这些不同事物间的共同点, 如自行车...
  • Class文件解读(一)

    2019-06-18 07:34:51
    2019独角兽企业重金招聘Python工程师标准>>> ...
  • .java&.class&.jar

    2016-05-29 13:27:55
    .java为Java的源文件后缀,编写的代码需要写在.java文件中。 而.class是字节码文件,是.java源文件通过javac命令编译后生成的文件。 Java虚拟机就是去运行.class文件从而实现程序的运行。
  • Class&Struct

    2019-06-26 09:38:51
    目录 1.类与结构 3.对象 4.结构 5.继承 6.多态 7.抽象类、密封类及类成员 8.静态类和静态类成员 9.访问修饰符 10.字段 11.常量 12.属性 13....
  • 理解Class的关键所在

    2018-05-15 17:37:41
    1.什么是Class类&amp;Class类的作用Class类说变了也是一个类,只不过是一个比较特殊的类。特殊在哪里呢?特殊在这是一个在类加载过程中由虚拟机生成的,由于表示被加载类的类型信息的对象。简单地说,我们创建一...
  • Class & 继承 & 原型 & 原型链Class类的声明继承instanceof 类型判断原型 & 原型链 整个七月到八月真是一堆事情,现在终于有空了,静下心复习一段时间刷刷面试题,准备去面试找工作了,希望在国庆...
  • Java中Class对象详解

    万次阅读 多人点赞 2018-06-01 14:50:40
    从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RT...
  • SpringBoot pom.xml配置文件详解

    万次阅读 2019-09-03 22:30:58
    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.or...
  • java经典代码片段

    千次阅读 2019-03-14 09:30:47
    java经典代码片段 写这篇也是用于学习 ... import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException;...import java.io.FileOutputStream;...import java.io.IO...
  • Java - Delegation Hierarchy Algorithm

    万次阅读 2019-03-22 18:17:15
    分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!...In this article, we will discuss about Types of Class Loaders and How Class Loader uses Parent delegation Algorithm to load ...
  • jQuery修改class属性

    万次阅读 2018-08-25 11:02:33
    注意:对于元素来说,class属性可以有多个值.该方法不会移除已经存在的值,而是在原有的基础上追加一个或多个class属性. 2.removeClass(); 移除样式 3.hasClass() 包含某个样式 4.$(“#xxx”).attr(“class...
  • 怎样加Java文件编译成class文件

    万次阅读 2018-06-25 10:26:29
    1.打开cmd,找到jdk安装的bin目录下,如图2,然后找到要编译的Java文件,我的Java文件在E:\workspaces\portal_one\JUnit_Test\src\main\java\com\baidu\test\dome\loader\Test.java;使用命令为Javac E:\workspaces...
  • Class类型参数(详解)

    万次阅读 2014-12-09 16:22:59
    T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class。如果将被建模的类未知,则使用 ClassClass 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每...
  • Class T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class。如果将被建模的类未知,则使用 Class。 public final class Class extends Object implements java.io.Serializable, ...
  • class文件反编译工具及使用

    万次阅读 2020-06-23 11:24:57
    碰到一个大坑就是现网环境只有class文件,但是公司代码又不是最新的,所以接收处理需求的时候就会代码导致不一致,所以没办法只能把现网的class文件拿回来进行反编译。这里也是在网上找的反编译工具,感觉挺好用的...
  • Android Studio:xxx is not an enclosing class 错误的解决方法这个问题一般出现在内部类中,若要创建内部类的实例,需要有外部类的实例才行,或者是将内部类设置为静态的,添加 static 关键字
1 2 3 4 5 ... 20
收藏数 8,401,702
精华内容 3,360,680
关键字:

class