欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对象与类(二)

程序员文章站 2022-04-05 17:11:09
...

1.8 static关键字

成员变量+static=静态变量

当我们在设计类的时候 发现多个对象中有共享数据的时候 我们就可以把这个共享的数据 定义为静态的

像name age虽然每个对象都有 ,但是值不一定一样           对象的特有数据->成员变量

像country虽然每个对象也都有 ,但是值一样          对象的共有数据-> 静态变量

上述可以知道 共有的数据存在于一个特定的空间→── 静态方法区

成员函数+static=静态函数

静态函数意味着就是对象的共有行为吗?不行的
    我们当前的成员函数如果不访问任何成员变量的情况下 这个函数就可以定义为静态的
    这就意味着 静态函数不能直接调用当前类中的成员变量 无法从静态上下文中引用非静态
    为啥?静态的生命周期要长于对象

所以 静态是优先于对象存在的
    静态也称之为是类的成员,我们可以直接通过类去调用
    类.静态成员

class StaticDemo{
    public static void main(String[] args){
        Chinese c1=new Chinese();
        Chinese c2=new Chinese();
        Chinese c3=new Chinese();
        //通过 对象.变量  
        //1.先去堆内存中对象的所属空间里找
        System.out.println(c1.name);    //成员变量
        //2.再去静态方法区中该对象所属类的空间里找
        System.out.println(c1.country); //静态变量

        //通过 对象.函数
        //1.先去非静态方法区中该对象所属类的空间里找
        c1.show();
        //2.再去静态方法区中该对象所属类的空间里找
        c1.haha();

        System.out.println(Chinese.country);
        Chinese.haha();
        //Chinese.show();
        System.out.println(Chinese.momo);
        System.out.println(Chinese.kaka);
    }
}
class Chinese{
    static int momo;
    static boolean kaka;
    String name;    //姓名
    String age;     //年龄
    static String country="China"; //国籍
    //无法从静态上下文中引用非静态
    public void show(){
        String name="旺财";
        /*
        成员函数内部在调用变量时的顺序:
        1.先找局部变量
        2.去堆中对象空间中找
        3.去静态区该对象所属类的空间里找
        
        我要喝水 水从哪里来
        1.如果你的嘴里已经有水 直接喝
        2.如果你的嘴里没水 杯子里有水 拿杯子喝 
        3.如果你的嘴里没水 杯子没水 去饮水机 
        (先不考虑继承的情况下)
        */
        System.out.println(name+age+country);
    }
    public static void haha(){
        System.out.println("哈哈");
    }
    public static void main(String[] args){

    }
}

为什么主函数是静态的?
        主函数是程序的入口,优于其它运行
        假设主函数是非静态的 那么必须先创建对象 才能调用主函数

 静态变量有没有默认初始化值?有  (运行时常量 永久代 JVM)
    也有显示初始化

 类的分类:

            实体类:
            就是为了描述一个事物 Person Point
            类中内容基本上都是成员函数/成员变量
            也会而存在一个静态成员
           工具类
            提供一些已经被实现好的功能 向外部供应
            所以工具类中基本上全都是静态函数
            类.Xxx 类.Xxx() Math Arrays
            为啥工具类中都是静态?
            1.共有的
            2.长时间存在
            3.加载一次 后期随便使用
            一个道理:
                当我们钉一个钉子的时候 找榔头
                你是造一个榔头 还是用已存在的榔头?
            如果工具类可以被创建对象 是不是就想用的时候去创建
                效率较低
           主类/测试类
            主要用于运行/测试代码
            这个类中会有主函数的存在
            实体类是可以存在主函数的 但是不推荐
            工具类一般不会存在主函数

1.9 对象的内存图解III

步骤:

1.javac 将Java源代码进行编译 生成字节码文件
    2.java 将字节码文件加载进虚拟机中 开始运行程序
        字节码具体被加载在方法区里面
        方法区可以大致分为 非静态方法区/静态方法区
        所有非静态的代码(二进制)内容加载进非静态去
        所有静态的代码(二进制)内容加载进静态区
        JVM接下来会根据参数(java 字节码文件名(类名)) 去静态区找主函数
        将主函数代码加载进虚拟机栈 开始运行
    3.后面的和之前一样

 

对象与类(二)

 

1.10 静态变量与成员变量的区别

1.生命周期
        成员变量随着对象的创建而创建 随着对象的消亡而消亡
        静态变量随着类的加载而创建 随着程序结束而消失
    2.调用方式
        成员变量必须先创建对象 在通过对象去调用
        静态变量可以被对象调用 也可以直接用类调用
    3.存储位置
        成员变量存在于堆内存中对象的所属空间里
        静态变量存在于静态方法区中类的所属空间里
    4.命名
        成员变量-对象的特有属性
        静态变量-对象的共有属性 类成员

1.11 代码块

代码块 { ... }
    
    局部代码块:存在于函数当中(包括函数) for(){...} if(){...}
    
    构造代码块:直接在类中出现的{...}
        当对象创建一次 构造代码块执行一次
        作用等同于构造函数

    静态代码块:直接在类中出现的static{...}
        当类被加载的时候 仅且只执行一次
        作用于 对类进行一些初始化操作 JDBC

1.12 单例模式

设计模式:就是我们的前辈们总结出来的一些编码技巧
    它并不是随着Java的诞生而诞生的
    它是由Java的广大使用者总结出来的一套编码经验
    常见26种

    单例模式:使用场景是 某一个类只能创建一个对象
    比如某一个朝代的皇帝 只能是唯一的
    1.既然只能创建一个对象的话 就得不能让外界去创建对象
        限制使用new不现实
        只能从对象的创建流程中考虑 只要有一个步骤不行 对象就创建不出来
        开辟空间分配地址 是由计算机底层决定 我们也控制不了
        构造函数执行  只需要将构造函数私有化即可
    2.既然外界不能创建对象 我们还得保证对象的创建
        所以我们只能在类内部创建对象
        Single s=new Single();
        能否写成 成员变量的形式?
        所以private static

//饿汉式 比较急 所以直接返回对象
/*
class Single{
    private static Single s=new Single();
    private Single(){}
    public static Single getInstance(){
        return s;
    }
}
*/
//饱汗式 比交满 不急 判断一下
class Single{
    private static Single s;
    private Single(){}
    public static Single getInstance(){
        if(s==null){
            s=new Single();
        }
        return s;
    }
}

 

class SingleTest{
    public static void main(String[] args){
        Single s1=Single.getInstance();
        Single s2=Single.getInstance();
        //s2=null;
        Single s3=Single.getInstance();
        System.out.println(s1==s2);
        System.out.println(s2==s3);
    }
}


    3.内部创建出对象 还得向外界提供
        因为private 外界不能直接访问
        所以见解 向外界提供一个函数 外界通过调用函数获取对象

1.13 继承

继承由来是什么:

当我们在定义若干个类的时候,发现某一些类中具有相同的属性和行为
        那么,我们就可以将这些相同的部分进行抽取,独立生成另外一个类,那么这个生成出来
        的类我们称之为是父类,其他的被抽取内容的类称之为子类


      子类与父类之间就是所谓的继承关系 用 extends来表示
    那么在现实生活中,父与子之间的一对多 还是多对多的关系?
    所以 在Java当中 继承是单继承(一个子类只能有一个父类,但是一个父类可以有若干个子类)
    当然,在C++中,继承是多继承的,不太符合实际的社会问题,所以Java更加符合现实编程
    (不代表Java当中就没有多继承的时候!如果是类与类之间 必须是单继承;如果是接口与接口之间,可以是多继承)
    既然有了继承,那么在Java当中就有了继承体系
    (既然有了父子关系,是不是就产生出了族谱这个东西)
    先说一点:我们常用的继承体系 异常体系 集合体系 IO体系 网络体系 多线程体系

 

对象与类(二)

 

 

class ExtendsDemo02{
    public static void main(String[] args){
        Zi zi=new Zi();
        System.out.println(zi.num1);//20
        System.out.println(zi.num2);//30
        System.out.println(zi.num3);//50
        zi.show();
        zi.sing();
    }
}
//子父类中成员变量的特点
/*
class Grandfather{
    int num1=100;
    int num4=200;
}
*/
class Fu {//extends Grandfather{
    int num1=10;
    static int num2=40;
    static int num3=50;
    Fu(){
        super();//Object(){} 显示初始化父类空间中的成员变量
        System.out.println("Fu constructor1......");
    }
    Fu(int num){
        System.out.println("Fu constructor2......");
    }
    void sing(){
        System.out.println("Fu sing......");
        System.out.println("爸爸我会唱红歌");
    }
}
class Zi extends Fu{
    int num1=20;
    static int num2=30;
    
    Zi(){
        this(0,0);
        System.out.println("Zi constructor1......");
    }
    Zi(int num1){
        this(0,0);
        System.out.println("Zi constructor2......");
    }
    Zi(int num1,int num2){
        super();
        System.out.println("Zi constructor3......");
    }
    void show(){
        //局部变量和成员变量如果重名了 this区分
        System.out.println(num1+","+num2+","+num3);
        //局部变量/成员变量和父类变量重名了 super区别 super.xxx => 你爸爸的xxx
        System.out.println(super.num1+","+super.num2+","+num3);
        //System.out.println(super.super.num1);
        //System.out.println(num4);
    }
    @Override
    void sing(){
        System.out.println("Zi sing......");
        System.out.println("儿子我会唱摇滚、民谣、爵士、蓝调、电子");
    }
}

在Java继承体系当中,所有类的最终父类都是Object!Object就不存在爸爸了
    如果我们在定义一个类的时候,没有显著声明父类的时候 那么该类的父类默认是Object

 

注意一点:在分析设计继承的时候 一定要符合社会常识问题
            子类 和 父类 之间 必须是 is a 关系 子类必须父类的一种 同一系列的
            she is a Girl  ; he is a boy ; he is a ladyboy ; 旺财 is a Dog
        所以,千万不要为了获取某一个类的功能而把这个类叫爸爸!

 

子父类中成员变量/静态变量的特点:

如果只有子类有且非私有 那么就调用子类的
        如果只有父类有且非私有 那么就调用父类的
        如果子父类都有且非私有 那么就调用子类的
        (成员变量之间 是不存在重写关系的!!!)
        子类.属性 顺序:子类对象成员->子类静态->父类成员->父类静态
        子类成员函数在内部调用变量时 局部变量->子类对象成员->子类静态->父类成员->父类静态

 

子父类中构造函数的特点:

现象:子类的构造函数在调用运行的时候 先执行父类的构造函数
        在子类的构造函数当中,有一句默认的super(...)隐藏了,而且这句代码必须是在第一行
        对super的调用必须是构造器中的第一个
        为什么?道理很简单 儿子向老爸要钱,那么老爸是不是得先准备一下钱
        既然子类继承自父类 那么必然会继承到父类当中的一些数据
        所以,在子类构造函数之中,必须先让父类把这些数据进行一些初始化才能继承给子类
        注意:父类的构造函数被调用,但不代表父类就被创建对象了!
              所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用
        并且注意super(...) 如果父类没有默认无参构造函数 那么子类构造函数中super()失效了
        所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(...)

 

对象与类(二)

 

        this(...)是当前类中 本类构造函数调用本类构造函数的方式
        super(...)是本类构造函数调用父类构造函数的方式

 

 

对象与类(二)

都必须在第一行 那么这两冲突不?


        如果本类构造函数当中不存在调用关系 那么每一个本类构造函数第一句都是super(...)
        如果本类构造函数当中存在调用关系,那么最后被调用的那个构造函数第一句绝对是super(...)
        this(...)的调用是单向的还是递归的?是单向的,那么最后被调用的第一句绝对就是super(...)

子父类中成员函数的特点:
        如果只有子类有且非私有 那么就调用子类的
        如果只有父类有且非私有 那么就调用父类的
        如果子父类都有且非私有 那么就调用子类的(函数重写)

 

函数重写

在子父类中,同名函数
    函数有什么组成:函数声明(权限 类型 返回值类型 函数名 参数列表)+函数体({}里面的内容)
    重写的意义在于哪?在于子类继承了父类的函数声明(功能),但是子类可以将该函数的具体实现进行优化或更改

 1.保留父类的功能声明 子类可以进一步优化
        2.保留父类的功能声明 子类可以重新定义

重写当中应该注意到的一些细节:
   

    1.函数重名 但是参数列表不同 不构成重写关系
    2.函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
    3.子类重写父类函数时,权限>=父类权限
    4.当然 如果父类函数权限为private 子类压根就继承不到 何谈重写

 

1.14 抽象类

抽象类:模糊不清的类 不具体的类
    当我们在抽取一个父类的时候,发现子类当中的一些共同方法在父类中无法进行具体的实现
    并且这些方法只能在子类中具体实现时,父类当中的这些函数就只保留函数声明即可,不必写函数体
    那么此时这个函数就是 抽象函数! 有抽象函数的类 就是抽象类!

 

特点:

   1.抽象类能否创建对象?不能 对象本身是一个具体的东西 而抽象类中含有不具体的内容
    2.抽象类必须作为父类存在吗?必须 抽象类就等着被继承呢!
    3.抽象类和一般类有什么区别?就是一般类的特殊情况
        唯一的区别只在于抽象类中有抽象函数!
    4.抽象类中必须有抽象函数吗?不一定 AWT界面开发
    5.abstract这个关键字不能和那些关键字共存?
        private 抽象函数就等着被子类重写实现呢!
        static  静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据
              

1.17 多态

多种状态:就是指一个对象可以有多种状态(他在继承体系中的位置变化)
    D->C->B->A->Animal
    位置的变化只能是向上变 但不能低于自身
    对于C而言 可以当做B来看 也可以当做A来看 也可以当成Animal
        小明        男人             人     动物
    小明的学校开家长会 小明不想让他爸爸去 他让大明去 大明就是小明他哥
    大明冒充Dad去参加家长会的话,那么所表现出来的行为 是不是应该符合他爸行为
    不同的视角 不同的角色

无论是在哪个视角场合 对象本身变了没有?只不过我们需要对象在不同的场合表现出相对应的行为
    在Java当中 多态代码表现 就是 父类引用指向子类的对象

class DuoTaiDemo01{
    public static void main(String[] args){
        //父类引用指向子类的对象
        Dady d=new Son();
        d.chouyan();
        d.hejiu();
        d.tangtou();
        //d.lol();
        System.out.println(d.num);
        d.xiToufang();
    }
}
class Dady{
    int num=20;
    void chouyan(){
        System.out.println("爸爸抽烟~");
    }
    void hejiu(){
        System.out.println("爸爸喝酒~");
    }
    void tangtou(){
        System.out.println("爸爸烫头~");
    }
    void xiToufang(){
        System.out.println("爸爸洗头房~");
    }
}
class Son extends Dady{
    int num=10;
    void chouyan(){
        System.out.println("儿子抽烟~");
    }
    void hejiu(){
        System.out.println("儿子喝酒~");
    }
    void tangtou(){
        System.out.println("儿子烫头~");
    }
    void lol(){ //对象的特有行为
        System.out.println("儿子玩lol~");
    }
}

 

 

多态的前提:继承 重写
    多态的好处:对代码的功能进行了可扩展性
        子类对象可以当做父类对象去使用 但是有限制 只能调用父类函数或重写的函数
        不能使用子类特有的行为

多态当中 成员变量的特点:只能访问父类中的成员变量
    多态当中 成员函数的特点:


        如果子类没有重写 且父类中有 调用父类的
        如果子类有重写 调用子类重写的
        如果不存在重写 父类没有 那就报错了!

class DuoTaiDemo02{
    public static void main(String[] args){
        Dog d=new Dog();
        Cat c=new Cat();
        Pig p=new Pig();
        feed(d);
        feed(c);
        feed(p);
    }
    //Animal a=new Dog();
    //Animal a=new Cat(); 向上类型转换
    public static void feed(Animal a){
        a.eat();
        //ClassCastException 类型转换异常
        //判断对象的本质类型 instanceOf
        if(a instanceof Pig){
            Pig pp=(Pig)a;
            pp.gongBaiCai();
        }
    }
    /*
    public static void feed(Pig p){
        p.eat();
    }
    public static void feed(Cat c){
        c.eat();
    }
    public static void feed(Dog d){
        d.eat();
    }
    */
}
abstract class Animal{
    static abstract void eat();
    abstract void jiao();
}
class Pig extends Animal{
    void eat(){
        System.out.println("猪啥都吃......");
    }
    void jiao(){
        System.out.println("猪哼哼哼......");
    }
    void gongBaiCai(){
        System.out.println("猪拱白菜......");
    }
}
class Dog extends Animal{
    void eat(){
        System.out.println("狗吃狗粮......");
    }
    void jiao(){
        System.out.println("狗汪汪汪......");
    }
    void lookDoor(){
        System.out.println("狗看家~......");
    }
}
class Cat extends Animal{
    void eat(){
        System.out.println("猫吃鱼......");
    }
    void jiao(){
        System.out.println("猫喵喵喵......");
    }
    void catchMouse(){
        System.out.println("猫捉老鼠~......");
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关标签: 知识点总结