精华内容
下载资源
问答
  • JS es6的Class类详解

    万次阅读 多人点赞 2020-09-05 10:17:18
    文章目录JS es6的Class类详解class基本语法Class的基本语法之constructorClass的基本语法之类的调用方式Class的基本语法之getter和setterClass的基本语法之类的属性名Class的基本语法的特别注意点Class的静态属性和...

    JS es6的Class类详解

    class基本语法

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数和原型的组合模式.ES6 提供了更接近传统语言(java)的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

    class point{
    	constructor(x,y){
            this.x=x;
            this.y=y;
        }
        play(){
            console.log("我会玩");
        }
    }
    

    ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

    注:“语法糖”:是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。

    ES6 的class与ES5写法的几个核心注意点:
    ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
    类的所有方法都定义在类的prototype属性上面。
    定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了
    方法之间不需要逗号分隔,加了会报错
    ES6的class使用方法与ES5的构造函数一模一样

    //类的所有方法都定义在类的prototype属性上面。
    class piont{
        constructor(){
    		//
        }
        play(){
            
        }
    }
    //上述代码等价于
    point.prototype={
        constructor() {},
        play(){};
    }
    
    //在类的实例上面调用方法,其实就是调用原型上的方法。
    class Ba{
    	//
    }
    let b=new Ba();
    b.constructor===Ba.prototype.constructor//true
    

    另外:ES5 的构造函数Point,对应 ES6 的Point类的构造方法。

    由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign方法可以很方便地一次向类添加多个方法。

    class ponit{
        constructor(){
            
        }
    }
    Object.assign(Point.prototype,{
    	play(){};
    })
    //Class直接定义的方法之间不需要逗号分隔,加了会报错. 但是这里是Object.assign的方法格式, 这里面需要往Point.prototype里面添加的方法就需要符合对象的默认格式
    

    类的内部所有定义的方法,都是不可枚举的(non-enumerable)。通过Object.assign方法往类的原型上添加的方法,constructor不可枚举, 其他的可以枚举

    Class的基本语法之constructor

    constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

    constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象
    (得是在创造class时就定义设置的, 在创造完class后,通过Object.assign的方式是没法改变构造函数的返回值的).

    Class的基本语法之类的调用方式

    类必须使用new调用,否则会报错。这是它跟普通构造函数 ( 普通构造函数完全可以当做普通函数使用 ) 的一个主要区别,后者不用new也可以执行。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9USZMu4q-1599271907892)(C:\Users\dell\Desktop\凯文的前端博客\images2\class1.png)]

    Class的基本语法之getter和setter

    与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

      class demo{
                constructor(age){
                    this.age=agie;
                    this._age=age;
                }
                get age(){
                    return this._age;
                }
                set age(value){
                    this._age=value;
                    console.log("年龄"+value);
                }
            }
            let kevin=new demo(9);
            kevin.age=18;
            console.log(kevin.age);
    
    Class的基本语法之类的属性名

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1iEAo4qQ-1599271907895)(C:\Users\dell\Desktop\凯文的前端博客\images2\class2.png)]

    上面代码中,Square类的方法名getArea,是从表达式得到的。

    Class的基本语法的特别注意点

    (1)严格模式

    类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。

    (2)不存在提升

    new foo();

    class foo{};

    上面代码中,Foo类使用在前,定义在后,这样会报错,因为 ES6 不会把类的声明提升到代码头部。

    (3)name 属性

    class point{

    }

    point.name//point

    由于本质上,ES6 的类只是 ES5 的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性。

    (4)this 的指向

    类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWvVyll7-1599271907897)(C:\Users\dell\Desktop\凯文的前端博客\images2\class3.png)]

    printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。

    解决办法:

    一个比较简单的解决方法是,在构造方法中绑定this,这样就不会找不到print方法了。

    另一种解决方法是使用箭头函数。箭头函数位于构造函数内部,它的定义生效的时候,是在构造函数执行的时候。这时,箭头函数所在的运行环境,肯定是实例对象,所以this会总是指向实例对象。

    class Logger{
        constructor(){
            this.printName=this.printName.bind(this);
            //但是请注意bind之后返回的函数里面的this就永久锁死了问题:!!! !!! 坚决别用 
        }
    }
    //箭头函数
    class Obj{
        constructor(){
            this.getThis=()=>this;
        }
    }
    let o=new Obj();
    o.getThis()===o//true
    

    Class的静态属性和方法

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

     class Person{
                static sum=0;
                constructor(){
                    this.add();
                }
                add(){
                    Person.sum++;
                }
            }
            let kaiwen=new Person();
            console.log("当前的聊天室人数为:"+Person.sum);
            //作用:当没有实例化的时候,我们可以通过静态的属性和方法去获取一些信息
     // 注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。静态方法可以与非静态方法重名。
    

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

     class Person{
                constructor(name){
                    this.name=name;
                    this.sex="男";
                }
            }
            class Student extends Person{
                constructor(name,age){
                    super(name);
                    this.age=age;
                }
            }
            let s=new Student("张三",11);
            console.log(s.name);
            console.log(s.age);
            console.log(s.sex);
    

    Class的私有方法和私有属性

    私有方法和私有属性:是只能在类的内部访问的方法和属性,外部不能访问。
    这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现。

    _bar方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法

    下面代码中的写法不仅可以写私有属性,还可以用来写私有方法

     class Cat{
                #eyes="眼睛";
                static pai(){
                    console.log("凯文");
                }
                say(){
                    Cat.pai();
                    console.log("猫有一双大大的"+this.#eyes);
                }
            }
            let kate=new Cat();
            kate.say();
    

    私有属性也可以设置 getter 和 setter 方法。

    私有属性不限于从this引用,只要是在类的内部,实例也可以引用私有属性。

    构造函数的新属性

    ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

    私有属性也可以设置 getter 和 setter 方法。

    私有属性不限于从this引用,只要是在类的内部,实例也可以引用私有属性。

    构造函数的新属性

    ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rSe8aqiI-1599271907900)(C:\Users\dell\Desktop\凯文的前端博客\images2\class4.png)]

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

    千次阅读 多人点赞 2020-02-02 19:40:08
    python中class 定义与使用 在学习python中这一部分也是非常常用的,的定义类似于函数却又不同于函数,class 定义一个, 后面的类别首字母推荐以大写的形式定义,比如Calculator. class可以先定义自己的属性...

    ☞☞☞点击查看更多优秀Python博客☜☜☜

    python中class 类定义与使用

    在学习python中类这一部分也是非常常用的,简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的,为什么要使用类,你可以和之前没有类的时候进行比较,比如和结构化编程比较,有了类有什么好处,总结就是封装、继承、多态,这些要你自己理解,越高级越抽象,越接近人的思维,越容易理解与使用,慢慢体会

    类的定义类似于函数却又不同于函数,class 定义一个类, 后面的类别首字母推荐以大写的形式定义,比如Calculator.
    class可以先定义自己的属性,比如该属性的名称可以写为 name=‘Good Calculator’.
    class后面还可以跟def, 定义一个函数.比如def add(self,x,y): 加法, 输出print(x+y).
    其他的函数定义方法一样,注意这里的self 是默认值.

    class的定义

    class Calculator:       #首字母要大写,冒号不能缺
        name='Good Calculator'  #该行为class的属性
        price=18
        def add(self,x,y):
            print(self.name)
            result = x + y
            print(result)
        def minus(self,x,y):
            result=x-y
            print(result)
        def times(self,x,y):
            print(x*y)
        def divide(self,x,y):
            print(x/y)
            
    

    上述代码就是一个类的定义方法,其中运行结果为:

    """"
    >>> cal=Calculator()  #注意这里运行class的时候要加"()",否则调用下面函数的时候会出现错误,导致无法调用.
    >>> cal.name
    'Good Calculator'
    >>> cal.price
    18
    >>> cal.add(10,20)
    Good Calculator
    30
    >>> cal.minus(10,20)
    -10
    >>> cal.times(10,20)
    200
    >>> cal.divide(10,20)
    0.5
    >>>
    """"
    

    注意:定义自变量cal等于Calculator要加括号“()” ,cal=Calculator()否则运行下面函数的时候会出现错误,导致无法调用.

    class 类 init 功能(初始)

    __init__可以理解成初始化class的变量,取自英文中initial 最初的意思.可以在运行时,给初始值附值,

    运行c=Calculator(‘bad calculator’,18,17,16,15),然后调出每个初始值的值。看如下代码。

    class Calculator:
        name='good calculator'
        price=18
        def __init__(self,name,price,height,width,weight):   # 注意,这里的下划线是双下划线
            self.name=name
            self.price=price
            self.h=height
            self.wi=width
            self.we=weight
    
    """"
    运行结果:
    >>> c=Calculator('bad calculator',18,17,16,15)
    >>> c.name
    'bad calculator'
    >>> c.price
    18
    >>> c.h
    17
    >>> c.wi
    16
    >>> c.we
    15
    >>>
    """"
    

    如何设置属性的默认值, 直接在def里输入即可,如下:

    def init(self,name,price,height=10,width=14,weight=16):查看运行结果,
    三个有默认值的属性,可以直接输出默认值,这些默认值可以在code中更改,
    比如c.wi=17再输出c.wi就会把wi属性值更改为17.同理可推其他属性的更改方法。

    class Calculator:
        name='good calculator'
        price=18
        def __init__(self,name,price,hight=10,width=14,weight=16): #后面三个属性设置默认值,查看运行
            self.name=name
            self.price=price
            self.h=hight
            self.wi=width
            self.we=weight
    
     """"
    >>> c=Calculator('bad calculator',18)
    >>> c.h
    10
    >>> c.wi
    14
    >>> c.we
    16
    >>> c.we=17
    >>> c.we
    17
    """"
    

    **注意:**def init(self,name,price,height,width,weight): 注意,这里的下划线是双下划线
    学习来源:莫烦python
    本文章仅做个人学习所用,引用请标明“莫烦python”

    **文章导航:**

    零基础学Python教程
    在这里插入图片描述

    展开全文
  • Class类 和 class对象(运行时的类型信息)

    万次阅读 多人点赞 2018-12-05 11:28:07
    每个的运行时的类型信息就是用Class对象表示的。它包含了与有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RTTI(运行时类型识别,Run-Time Type Identification),多态是...

    什么是类?可以理解为。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

    展开全文
  • Class类简介

    万次阅读 多人点赞 2018-05-25 19:39:41
    1、Class类简介: &nbsp;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_SERVICE的IBinder对象的代理

    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/

    展开全文
  • Java中的Object类和Class类

    千次阅读 多人点赞 2019-04-24 19:59:33
    在Java中,无论是类还是接口,它们在JVM的内存逻辑模型中都会存在Super和Class指针,分别指向根类(Object类)和反射类(Class类) 在这一篇blog中会了解到很多常用方法,建议大家看api 1. 位置和内容 Object类和...
  • Java反射 Class类常用方法详解

    万次阅读 多人点赞 2018-05-19 18:47:49
    1.返回Class类对应的实体类的相关的Class类的方法:如果我们已经有了一个类的 Class类,可以使用下面的一些方法来获得它相关的类:(1)返回当前Class类对应的实体类的父类的Class类:public Class&lt;? super T&...
  • JS中Class类的详解

    千次阅读 多人点赞 2019-04-25 09:43:56
        在ES6中,class ()作为对象的模板被引入,可以通过 class 关键字定义。它可以被看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。     实际上是个“特殊的函数”,就像你能够...
  • es6 class类class类中constructor

    千次阅读 2019-02-20 16:00:43
    在es6 中的class关键字用于声明,在此之前js一直没有的概念,本文只要讨论class的与es5中对象的关系以及class中constructor的作用 关键字class ES6 的class可以看作只是一个语法糖,而本身可以看作一个构造函数...
  • java反射以及Class类类型

    千次阅读 多人点赞 2018-12-10 02:46:42
    java的反射机制: 在运行状态中,对于任意一个类,都能知道这个...1.Class类的使用   在面向对象的世界中,万事万物都是对象 普通数据类型不是面向对象 比如int long 但是它们的包装类型 integer Long是对象 ...
  • python——class类和方法的用法详解

    千次阅读 多人点赞 2020-08-07 16:17:00
    因为一直不太清楚面向对象的和方法的编程思想,所以特地补了一下python-class的知识,在这里记录和分享一下。 文章目录和方法的概念和实例1.python:`class`2.的构造方法`__init__()`3.中方法的参数`self...
  • Linux查找class类所在jar包

    千次阅读 2019-04-30 17:33:00
    在Eclipse中可以使用Ctrl+Shift+T查找, 但是如果所在的jar包不在Build Path中, 则是找不到的。 另一种方法是到网上搜索或者专门的网站去查找, 但只能查找公共仓库上的所在jar包, 如果是自己编写的私有的...
  • ES6专题 class类继承super详解

    万次阅读 2020-03-12 23:01:05
    super作为对象在普通方法中...class A{ // 属性应该怎么写??? //#pA私有属性,static pA静态属性 pA = 123 //实例属性 p(){ return 3 } } //A.prototype.pA = 123 class B extends A{ constructor(){ ...
  • 获取Class类1、反射概述2、类的加载过程3、获取Class类的三种方式3.1 通过 class.forname()来获取Class对象3.2 通过类名.class来获取Class对象3.3 通过对象的getClass()来获取Class对象3.4如果是一个基本数据类型,...
  • Python中Class类与def函数的区别

    万次阅读 多人点赞 2019-07-17 18:16:34
    自己在编程过程中习惯用函数def来封装模块,但是换了环境后发现同事大多采用class实现封装,两者之间有什么...Class类的优点 Class的优点是可以保存状态,如果不能保存状态,就需要通过参数把相关信息传递过来。 '...
  • 三种方式如何获取到Class类

    千次阅读 2019-03-27 08:32:34
    三种方式如何获取到Class类 package com.test; public class Test1 { public static void main(String[] args) { //获取到Class类 try { //1.Class.forName("com.test.Sub"); //Class c = Class.for...
  • Java中Class类与Object类之间的关系

    千次阅读 2018-02-22 15:57:06
    Object类和Class类没有直接的关系。Object类是一切java类的父类,对于普通的java类,即便不声明,也是默认继承了Object类。典型的,可以使用Object类中的toString()方法。Class类是用于java反射机制的,一切java类,...
  • java.lang.Class类和反射机制创建对象

    万次阅读 2015-11-24 00:12:02
    java.lang.Class类  Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类...
  • Java中Class类详解、用法以及泛化

    万次阅读 2017-03-19 11:18:25
    在前面我们将类的加载的时候,类...前面的关于反射的文章,我们多次都用到了Class类,可以用这个类创建对应类的实例对象,这可以看做是Class类的一个作用。但是这个Class类和对应类本身又有什么联系和区别呢?比如new
  • java.lang.Class类详解

    万次阅读 多人点赞 2015-05-18 13:54:21
    虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。说白了,Class类对象就是封装了一个类的类型...
  • 简述Java中Class类的作用与快速理解

    万次阅读 2017-03-09 15:20:27
    在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。JVM利用运行时信息选择...Class类可以帮助我们在程序运行时分析类,说白了就是获取类中的值。...
  • 在js的中,可分为三种方法,constructor构造方法、静态方法与普通方法。 一、constructor构造方法 1.概念 的作用在于构建对象,而constructor构造方法就是用于构建对象实例。 2.使用方法 在使用new...
  • Python class类转字典

    千次阅读 2018-03-25 21:58:49
    有时候会需要从包装的里面取出需要的数据,但有不能直接取出来:可以通过如下代码,把class转换成字典:# 将class转dict,以_开头的也要 def props_with_(obj): pr = {} for name in dir(obj): value = getattr...
  • ID选择器与Class类选择器区别

    千次阅读 2018-11-21 14:13:39
    class和id选择器得区别:class选择器的值不是唯一的,我可以在多个标签共用一个class名 ID选择器: &lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="UTF-8...
  • 反射---获取Class类的4种方式

    万次阅读 2017-06-06 22:38:39
    随笔---------------------------------------获取Class类的4种方式----------------------------------------------------------------------------------------- 1.调用运行时类本身的.class属性 Class clazz = ...
  • es6 class类中的this指向

    千次阅读 2018-04-22 14:06:05
    this指向 的方法内部如果有this,默认指向的实例。 但单独使用该方法时,很可能会报错。class Logger{  printName(name = 'there'){  this.print(`hello ${name}`);  }  print(text){  console.log(text);...
  • 【深入Java虚拟机】之二:Class类文件结构

    万次阅读 多人点赞 2014-01-02 23:55:07
    Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现。不仅使用Java编译器可以把Java代码编译成存储字节码的Class文件,使用JRuby等其他语言的编译器也...
  • es6 javascript的class类中的 get和set

    万次阅读 2016-12-09 18:32:19
    与 ES5 一样, 在 Class 内部可以使用get和set关键字, 对某个属性设置存值函数和取值函数, 拦截该属性的存取行为。class MyClass { constructor() { // ... } get prop() { return 'getter'; } set prop...
  • es6新增了一种定义对象实例的方法,使用class关键字定义,与class相关的知识点也逐步火热起来,但是部分理解起来相对抽象,简单对class相关的知识点进行总结,更好的使用class。对于基本概念,请参见阮一峰老师的...
  • es6 javascript的class类的new的新特性

    千次阅读 2016-12-09 18:46:28
    Class 内部调用new.target, 返回当前 Classclass Rectangle { constructor(length, width) { console.log(new.target === Rectangle); this.length = length; this.width = width; } } var obj = new ...
  • jar包:phoenix-4.8.0-cdh5.8.0-server.jarclass:org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec命令:jar -vtf /opt/cloudera/parcels/CDH/lib/hbase/lib/phoenix-4.8.0-cdh5.8.0-server.jar | ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,541,472
精华内容 2,216,588
关键字:

class类