【JAVA】第八章 面向对象(2)

第八章 面向对象(2)

8.1 java内存详解

8.1.1 java内存

  • JDK1.8以前(不含1.8)JVM内存分为5块:程序计数器-堆-虚拟机栈-本地方法栈-方法区

1.程序计数器(program counter register):PC寄存器,
2.堆:由所有线程共享,运行时动态申请的内存都在堆里面分配,包括new的对象和数组(动态申请的内存使用完毕,Java有自动垃圾回收机制);JDK1.8之后,静态变量,常量池等也在堆中。
3.栈:每个线程拥有独立的栈;存放局部变量,对象引用,操作数栈,方法出口等;先进后出,被调方法结束后,对应栈区变量等立即销毁。
4.方法区:JDK8之前,由永久代实现,主要存放类的信息,常量池,方法数据,方法代码等
5.本地方法栈:主要与虚拟机用到native方法有关 ,多语言调用的时候使用,C,C++…执行底层代码

8.1.2 图示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

8.2 构造方法

8.2.1 构造方法概念

1.一个对象被创建的时候,构造方法用来初始化该对象,给对象的成员变量赋初值。
2.构造方法执行的时机:创建对象的时候执行。
3.作用:给对象的成员变量赋初始值。
4.分为有参构造和无参构造。
5. 格式:

修饰符 类名() {
  方法体(给成员变量赋初始值);
	}

6.特点:

1) 方法名必须和类名一致 如:Person类 构造方法名: Person() {}。
2)没有返回值,不需要返回值类型.连void都不要写
3) 默认被jvm调用使用,不能手动调用 new 构造方法();
4)构造方法必须跟在new关键字的后面

7注意事项:

1)创建类不提供空构造方法,创建对象的时候,主类会生成空构造,如果有,就不生成。
2)如果一个类提供了有参构造就不会再默认创造无参构造方法。一但创建了有参构造,优先创建无参构造,不然new对象的时候会报错。
3)构造方法是可以重载(方法名相同,参数列表不同)的,既可以定义参数,也可以不定义参数。

案例:Student类

public class Student {
    private String name;
       //空构造 - 如果我们不提供空构造,那么程序会默认生成一个,如果提供了,程序不再生成。
    public Student(){
       System.out.println("====================");
    }
     // 如果一个类提供了有参构造,那么就不会再默认创建无参数构造,
     // 使用时特别注意:一旦创建了有参构造, 优先创建无参数构造。
     //方法重载 - 有参数的构造方法, 创建对象的时候就可以直接使用有参数的构造实例化
    public Student(String name){
       this.name = name;
       System.out.println("有参数====================:"+this.name);
    }
    //2参数 3参数.....
    public Student(String name,int age){
       this.name = name;
       System.out.println("有参数====================:"+this.name+"年龄:"+age);
    }
                              
}

😁构造方法赋值和setter赋值的区别【面试题】

  1. 构造方法一般是new对象的时候使用,创建对象的同时就知道要为每个成员变量赋什么值,就用构造方法.代码更加简洁(一次)
  2. 创建完对象还要给私有成员赋值,修改私有成员变量的值,只能时候用setter方法. setter比构造方法更加灵活.(多次)
  3. 构造方法赋值一定比setter赋值优先。

8.2.2 成员变量初始化的过程

1.成员变量初始化的方式
  1. 默认初始化 private String name; // null
  2. 显示初始化 private String name = “rose”; // rose
  3. 构造方法初始化 private String name; Person(“jack”) // jack
2.三种初始化的顺序:
  1. 默认初始化优先执行 //不提供默认值
  2. 显示初始化 //提供默认值
  3. 构造方法初始化
3.构造方法初始化步骤:
  1. 类加载-> new - >初始化成员变量(不给值null / 给值直接赋值) -> 对象创建完成之后 - > setter赋值
  2. 后赋值会把先赋值给覆盖掉

8.2.3 标准JavaBean

  1. JavaBean是Java语言编写类的一种标准规范。符合JavaBean的类,称之为JavaBean(标准java类) 。
  2. 格式:
public slass 类名 {
      //1.成员变量(必须封装)
      //2.空构造方法(必须有)
      //3.有参构造方法(建议)
      //4.成员变量的getter 和 setter方法(必须有)
      //5.toString()
}
  1. 注意事项:
  1. 要求类必须是具体的和公共的- public class 类名
  2. 一定具有无参数的构造方法- public 类名() {}
  3. 成员变量都私有化,提供成员变量的set 和get 方法
  • 案例:
package com.its.constructor;

import java.util.Arrays;

public class Flower<toString> {
    private String name;
    private char color;
    private int price;


    //构造方法
    //无惨构造
    public Flower () {
    }

    //有参构造
    public Flower(String name,char color,int price) {
        this.name = name;
        this.color = color;
        this.price = price;
    }

   //成员变量的setter 和 getter方法
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }

    public void setColor(char color) {
        this.color = color;
    }
    public char getColor() {
        return this.color;
    }

    public void setPrice(int price) {
        this.price = price;
    }
    public int getPrice() {
        return this.price;
    }


    //toString
    public String toString() {
        return "name:" + this.name + "color:" + this.color + "price:" + this.price ;
    }
}

8.3 静态–static关键字

8.3.1 静态基础

  1. 静态:就是static,主要用来修饰java的变量(静态变量)和方法(静态方法)的关键字。一个变量或方法一旦被static修饰,它就是静态的内容。
  2. 基础案例:

创建一个Star类
属性: 姓名(name) 国家(country)
创建三个Star对象
对象1: 周杰伦 中国
对象2: 张国荣 中国
对象3: 王祖贤 中国

  • Star类:

public class Star {
    public String name;
       public static String country;
       @Override11    
       public String toString() {
       return "Star{" +"name='" + name + '\'' + country='" + country + "\" + '}';
    }
 }
  • Star测试
public class StarExample {
    public static void main(String[] args) {
        Star star1 = new Star();
        Star star2 = new Star();
        Star star3 = new Star();
        Star2 star22222 = new Star2();
        star1.name = "周杰伦";
        star1.country = "中国";
        star2.name = "张国荣";
        star3.name = "王祖贤";
        System.out.println(star1);
        System.out.println(star2);
        System.out.println(star3);
        System.out.println(star22222);
        }
}
  • 内存分析
    静态变量在内存中
  1. 有静态和无静态的区别:
  1. 无静态:如果某个类型的所有对象,都具有一个相同的属性值,那么这个属性值就没有必要在所有对象中,都存储一 份。还有坏处:浪费堆内存空间;维护难度大,一旦需要修改,就得修改所有的对象。
  2. 有静态:如果某个类型的所有对象,都具有一个相同的属性值,那么就在这个属性的定义上,加一个static静态关键 字。让该变量存储在方法区字节码的静态区中,避免了所有对象都存储相同数据的问题,节省了内存空间,将来维护容易。
  1. 静态变量的特殊性
  1. 静态变量比较特殊,有一个共享的类级别区域(静态区)专门存储当前的静态变量,和对象无关。无论初始化多少个对象,只要有一个对象给静态变量赋值,其他对象都是用这个值。
  2. 特殊:其它类中即使有相同的名字的静态变量,也不可以调用它。

8.3.2 静态变量的特点

  1. 静态变量属于类(直接可以通过类名访问静态变量),不会随着对象的变化而变化(内存位置)
    格式:
修饰符 static 变量类型 变量名;
  1. 调用方式:(最合适的调用方式) : 类名.静态变量
    3… 加载时机: 随着类(字节码文件加载方法区/元空间)的加载而加载。 静态变量随着类的加载进方法区。
  2. 静态变量优先于对象而存在。
  3. 静态变量被所有该类对象所共享。
  4. 可以通过对象名调用,但是会有警告 格式: 对象名.静态变量

8.3.3 静态方法

  1. 静态方法:在方法声明上,加static,就是静态方法—
public static返回值类型 方法名(参数列表){
}
  1. 调用方式:(最合适的调用方式) : 类名.静态方法名
  2. 静态方法不能访问非静态的变量(成员变量)以及非静态方法。 静态方法早于对象存在, 而非静态的变量(成员变量)以及非静态方法属于对象, 如果静态方法能访问非静态方法以及非静态的变量(成员变量),就相当于使用了一个 不存在的对象,有错误。
  3. 静态方法中不能存在this关键字 原因: this关键字表示本类当前对象。静态方法可以在对象创建之前调用。8 如果静态方法可以访问this关键 字,相当于在创建对象之前,就使用了对象本身—矛盾.

案例:

package com.mianObject;

public class Pig {
    public static String name;
    public static int weight;

    public static void eat() {
        System.out.println("爱吃粑粑");
    }
}
-----------------------
package com.mianObject;

public class PigExample {
    public static void main(String[] args) {
        Pig.name = "滔滔";
        System.out.println(Pig.name);
        Pig.eat();
    }
}

8.4 继承

8.4.1 概念

  1. 继承(单继承(C语言有多继承)–只有一个父类)是面向对象三大特征之一,继承就是让两个类之间产生关系,这种关系就是继承。
    继承的实现:
修饰符  class  子类名  extends  父类 名{ } 
  1. 继承会产生父子类,使得子类具有父类的属性(公开的)成员变量和方法。还可以在子类新定义属性方法。
  2. 向下关系,可以有“爷孙”关系,继承不代表所有父类的东西都能继承,private(私人的无法继承)
  3. JavaBean不可以做父类,因为属性都是私有的
  4. 一个类只能有一个父类,但是可以有多个子类。继承关系要合理。

案例:

package com.its.constructor;

public class Person {
    public String name;
    public String id;
    public int age;

    public Person(String name,String id,int age) {
        this.name = name;
        this.id = id;
        this.age = age;

    }

    public Person() {

    }


    public void sleep () {
        System.out.println("人会睡觉");
    }

    public void eat () {
        System.out.println("人会吃饭");
    }

    public void drank () {
        System.out.println("人会喝水");
    }

}

-------------------------
package com.its.constructor;

public class Teacher extends Person {
    public int workYear;
    public String jobSchool;

    public void teach() {
        System.out.println("老师传授知识");
    }

    @Override
    public void sleep() {
        System.out.println("老师睡得晚");
    }
}

------------------------------
package com.its.constructor;

public class Student extends Person {
    public String studentID;
    public String school;

    public void learn() {
        System.out.println("学生学习知识");
    }
}
---------------------------
package com.its.constructor;

public class Example {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        t.name = "张老师";
        t.jobSchool = "第二中学";
        t.workYear = 10;
        t.teach();
        System.out.println(t.name + "在" + t.jobSchool + "教书");


        Student s  = new Student();
        s.name = "小明 ";
        s.school = "第二中学";
        s.studentID = "197701020072";
        s.learn();
        System.out.println(s.name + "在" + s.school + "上学");
        
    }
}


8.4.2 继承的好处

  1. 优势
  1. 提高代码的复用性(多个相关类有相同的成员变量或者成员方法,可以提取出来放到父类中,父类中一般定义的内容都是这类事物的共性)
  2. 提高了代码的维护性(如果方法的代码需要修改,修改一个地方就可以了)
  1. 弊端:

提高了类与类的耦合性:继承让类与类之间产生了关系,类与类之间的耦合性增强(两个类之间的关系性增强)了,当父类发生变化时子 类实现也不得不跟着变化

  1. 应用场景

使用继承,需要考虑类与类之间是否存在is…a的关系,不能盲目使用继承 is…a 的关系:谁是谁的一种.

  1. 练习:

程序员类Coder:姓名name、年龄age、工号number、工资salary、 工作work
项目经理Manager:姓名、年龄、工号、工资、奖金bounds、 工作 、开会
解决:将程序员和项目经理向上抽取一个“员工类” Employee

代码:

package com.block;

public abstract  class Employee {
    public String name;
    public int age;
    public String number;
    public Double salary;

    public Employee(){

    }

    public Employee(String name,String number,Double salary){
        System.out.println("Employee抽象方法中输出this:" + this);
        this.name = name;
        this.number = number;
        this.salary = salary;
    }

    public void work() {
        
    }
}

8.4.3 继承关系成员变量的访问

1. 不同名变量的访问
  1. 父子类中成员变量没有同名的情况时,不冲突(直接使用)
  2. 子类对象可以访问父类中所有非私有成员变量
    子类对象调用范围:
  • 子类局部范围找: 找有没有局部变量
  • 子类成员范围找: 找有没有成员变量
  • 父类成员范围找: 找父类有没有定义此成员变量
  • 如果都没有就报错(不考虑父亲的父亲…) 子类能使用父类的内容
  1. 父类对象:只能访问父类拥有的变量(父类不能访问子类信息)
2. 同名变量的访问
  1. 默认访问子类自己的变量
  2. 父子类中有成员变量同名的情况下,要访问父类成员变量,使用supper.变量名
    super:是一个关键字,建立在继承关系中,用来使用父类资源。代表当前调用对象的父类那部分空间的引用,不是一个对象,不能打印 当我们创建一个子类对象时候,其实底层会优先创建父类的内存地址。
    this:代表当前调用对象引用,可以打印,this即可以访问子类自己的成员变量,也可以访问父类的成员变量

案例:

public void showName() {
    System.out.println(name);
    System.out.println(super.name);
 }
3. 继承下的内存分析
  • 子类会默认调用父类的空构造器,给父类初始化
  • 父类要么没有构造器,要么有空构造器+构造器

8.4.4 继承中成员方法的访问

  • 子类对象:可以访问父类中所有成员方法
  1. 子类成员范围找 优先在自己类中找这个方法。
  2. 子类成员范围找不到就去父类中寻找,找到就用。
  3. 如果都没有就报错(不考虑父亲的父亲…)
  • 父类对象:只能访问父类中拥有的方法
  1. 父类对象:只能访问父类中拥有的方法
  2. 如果都没有就报错

8.4.5 方法重写

  1. 概念
  1. 子类对父类的同名方法的重新实现(子类中提供了一个和父类中一模一样方法声明),称之为方法的重写。方法的重写需要使用注解 @Override 标注
  2. 注解@Override:用来检测当前的方法,是否是重写的方法,起到【校验】的作用
  1. 重写的目的

为了增强父类方法的实现,父类方法实现不能满足子类的需求了,. 对父类方法的功能进行了拓展和维护。

  1. 重写的使用场景
  1. 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法.
  2. 即沿袭了父类的 功能,又定义了子类特有的内容 , 保留父类的实现方式:super.父类方法(实参)
  1. 注意事项
  1. 父类私有方法不能被重写 (子类看不到这个私有的方法)
  2. 子类方法访问权限不能更低(public > 默认 > private)

8.4.6 继承关系成员的访问

  1. 父类的构造方法子类不能继承,只能调用
  2. 子类会继承父类中的数据(成员变量),可能还会使用父类的数据。
  3. 所有子类初始化对象之前一定要先完成父类 数据的初始化.每一个子类构造方法的第一条语句默认都是: super() 表示访问父类的空参构造,父类继承过来成员都 赋的事默认值 每创建一个子类对象, 5都会调用父类的构造方法,目的就是为了初始化父类那部分成员变量.
  4. 构造器先创建对象,再做其他的操作,构造器之间的调用一定放在第一行,而且唯一只能调用一个,不管是父类的,还是自己的。
  5. 无论使用子类哪一个构造方法,都会优先调用父类的空参构造。

注意事项:

  1. 子类中所有的构造方法默认都会访问父类中无参的构造方法.
  2. 子类的构造方法中手动调用父类的其他构造,就不会默认访问父类的无参构造.
  3. 如果在子类构造方法中,手动调用父类构造方法,必须写在子类构造方法的第一条语句. 否则不能第一时间创建父类
    4.子类调用父类构造方法的格式: super([实参]);

this 和supper调用构造方法的区别

  1. this只能访问本类的构造方法. 格式: this([实参])
  2. super只能访问父类的构造方法. 格式: super([实参])
  3. this语句和super语句不能同时出现.this语句和super语句都必须出现构造方法的第一行
  4. 一个构造方法无论手动显示调用this语句还是super语句,系统都不在默认添加:super()
  5. 不要写出this语句的循环调用(不能在本类的空参构造中调用this())

8.4.7 this&super的使用方法

  1. 成员变量
    this.成员变量 - 既可以访问本类成员变量,也可以访问父类的
    super.成员变量 - 只能访问父类成员变量
  2. 成员方法:
    this.成员方法 - 既可以访问本类成员方法,也可以访问父类的
    super.成员方法 - 访问父类成员方法
  3. 构造方法:
    this(…) - 访问本类构造方法 this()
    super(…) - 访问父类构造方法 super()

8.4.8 继承的注意事项总结

  1. 私有的成员不能被继承(不能直接被访问),只能通过setter和getter方法操作.
  2. 父类中的构造方法,不能继承,但是可以【调用】父类的构造方法。super(实参)语句.
    原因:父类的构造方法需要和父类的类名一致、子类的构造方法需要和子类类名一致,父类和子类的类名不 一样。因此无法继承,名称有冲突。 Zi z= new Fu(); 编译报错 父类的构造方法用于给父类的成员变量赋值,子类的构造方法用于给子类的成员变量赋值,9 子类的成员变量 较多,使用父类的构造方法无法将子类中所有的成员变量都进行赋值,因此不继承父类的构造方法.

2.父类的构造方法,不能继承

8.4.9 Java语言中类继承的特点(面试题)

  1. java支持单继承,不支持多继承,java支持多层继承
  2. 单继承:一个子类只能继承一个父类(一个孩子只能有生物学上的亲爹)
  3. 不能多继承:一个子类不能同时继承多个父类4
  4. 可以多层继承:A类可以继承B类,B类可以继承C类,A类中拥有B、C类中的所有属性和方法。

8.5 代码块

8.5.1 概念

  1. 代码块:使用单独的大括号包起来的一段代码段。
  2. 定义在不同的位置,有不同的名称,有不同的作用,有不同的执行时机。有一些代码块有修饰符,根据修饰符不同也有不同功能的代码块。
  3. 格式:
[修饰符] {  }
  1. 分类: 局部代码块 --构造代码块–静态代码块–同步代码块(多线程的安全问题)

8.5.2 局部代码块(了解)

  1. 概念:定义在方法的方法体中的代码块
  修饰符  返回值类型 方法名 (形参){
     {局部代码块}
  }
  1. 作用:缩短局部变量的生命周期,及时释放内存空间,提升代码的运行效率
  2. 执行时机:所在方法被调用的时候执行,执行到局部代码块右花括号被回收
  3. 注意:- 代码块可以使用上面的所有资源 - 代码块内部的局部变量【资源】外部不能使用

案例:

package com.block;

public class Block {
    public static void main(String[] args) {
        int c = 30;
        //局部代码块
        {
            int a = 10;
            System.out.println(a);
            System.out.println(c);   //代码块可以使用它上面的资源
            //System.out.println(b); //代码块不可以使用它下面的资源
        }
        int b = 20;

        //一个方法中可以定义多个局部代码块
        {
            System.out.println("局部代码块");
        }
    }
}

8.5.3 构造代码块(了解)

  1. 概念:定义在类中方法外(直接定义在类体中)【成员变量位置】的代码块
修饰符 class 类名 { 
     { 构造代码块 }
      类的其他内容 
  }
  1. 作用:创建对象的时候给对象的属性值显性赋值(对成员变量赋值)
    显性赋值: 定义类的属性的时候人为给属性赋值
    比如:private String name = “金莲”; { name = “大朗”; }
  2. 执行时机:每次创建对象,就会执行构造代码块,执行时机比构造方法早.
  3. 执行特点:构造代码块,每次创建对象都会执行而且优先于构造方法执行
  4. 成员变量的初始化时机:默认初始化—>显性初始化 —>[3.构造代码块初始化] —>构造方法初始化

案例:

package com.block;

public class Block {
    
       public String name;
       public int age;
       //构造代码快,和成员变量同等级
       {
          name = "张三";
          age = 30;
           System.out.println("构造代码块……");
       }
      //空构造方法
       public Block() {
           
       }

    //构造方法
    public Block(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Block有参构造");
    }
}


8.5.4 静态代码块(重点)

  1. 概念:被 static 修饰的构造代码块叫静态代码块
   修饰符 class 类名 { 
       static{ 构造代码块 }类的其他内容 
    }
  1. 位置:定义在类中方法外(类体中)
  2. 作用:给类的静态变量显性赋值 --用来加载只需要加载一次的资源 【如加载数据库驱动】
  3. 执行特点:只执行一次【随着类的加载而加载】 字节码文件只加载一次,所以静态代码块也只执行一次
package com.block;

public class Block {

       public static String name;
       public int age;
       //构造代码快,和成员变量同等级
       static{
          name = "张三";
           System.out.println("静态代码块……");
       }
      //空构造方法
       public Block() {

       }
}

8.6 final关键字

  1. final是一个关键字,表示最终,主要用来修饰Java资源. 被final修饰的元素变成了最终元素,不能修改。 作用范围:可以修饰 变量 方法 类
  2. 变量: 最终变量 ------ 变量不能改变 【变相的成为了常量】 这就是所谓的常量符号
  • 特点:最终变量只能赋值一次 值不可改变 7
  • 常量符号命名规范: 全部大写,多个单词之间使用下划线连接
  1. 方法:最终方法 ----- 方法不能被改变【功能就定死】
  • 场景:父子之间,如果父类的方法不想被子类重写,就可以使用final修饰父类的方法
  • 特点:最终方法不可以被重写,可以被继承调用
  1. 类:最终类 不能改变
  • 场景:如果一个类你不想让他拥有子类,在定义这个类的时候使用final修饰即可
  • 特点: 不能被继承

8.7 权限(访问)修饰符

  • 用来限定资源的适用范围的修饰性词汇,叫权限修饰符,不同符号有不同的限定范围。
  1. public:公共的–没有范围
  2. protected:受保护的–本类和本包中使用
  3. private :私有的 限定范围是:本类中使用 默认的 : 啥也不写 限定范围: 本类和本包中使用
  4. 默认:只能在本包使用

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值