类和对象的关系

什么是类、什么是对象

  • 概述
    官方定义:
    类就是拥有相等功能和相同属性的对象的集合 – 抽象的
    对象就是类的实例 – 具体的
    个人理解:
    类是一个模板,它描述一类对象的行为和状态。- -例如 手机设计图纸
    对象则是类所描述的具体的存在,有状态和行为。- -例如 我手中的小米10旗舰版
    在这里插入图片描述
  • 举例:
    例1: 下图1中男孩想象中的女孩(girl) 就是类(class),而具体的每个女孩就是该类的对象(object):

    例2: 下图中汽车为类(class),而具体的每辆车为该汽车类的对象(object),对象包含了汽车的颜色、品牌、名称等。

创建类和对象

  • 先创建类再 new 对象
    既然类是对象的模板,那一定是先有类再根据类这个模板创建对象,所以我们先要来个类。下图右侧就是一个Dog类,左侧就是根据这个类创建的具体对象。
    在这里插入图片描述

  • 创建一个Dog类:

    public class Dog {
        //属性
        String breed;
        String size;
        String color;
        int age;
        //方法
        void eat(){
            System.out.println("狗吃骨头");
        }
        void run(){
            
        }
        void sleep(){
            
        }
        void name(){
            
        }
    }
    ---*---
    演示类,非标准类
    
  • 创建一个Dog对象:

    public class TestClass {
        public static void main(String[] args) {
            //通过 new 关键字创建了一个Dog对象,并把对象的引用赋值给了Dog类型变量 d
            Dog d = new Dog();
            //通过对象名直接访问对象属性并赋值
            d.breed = "德国牧羊犬";
            d.size = "大";
            d.color = "白色&橘色";
            d.age = -2;
            //查看对象的属性,调用eat方法
            System.out.println("品种:"+ d.breed);
            System.out.println("大小:"+ d.size);
            System.out.println("颜色:"+ d.color);
            System.out.println("年龄:"+ d.age + "岁");
            d.eat();
        }
    }
    ---*---
    输出结果:
    品种:德国牧羊犬
    大小:大
    颜色:白色&橘色
    年龄:-2岁
    狗吃骨头
    
  • 不合法的年龄 (初见封装)
    这时会出现了一个问题,通过对象名直接访问属性是不受控制的。比如年龄这个属性不可能为负数,但目前这样的访问方式是可以设置成负数的。所以我们要对属性进行控制,或者说保护。首先将所有的属性的访问权限设置为 private(私有),然后为每一个属性提供一对,public(公共) 的获取和修改属性的方法。这样我们在方法中就可以对其进行验证。

    public class Dog {
        //age属性私有化
        private int age;
    
        //提供访问 age 属性的 get和set方法
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
        //用if语句对输入的数据进行判断
            if (age<0 || age>50){
                System.out.println("输入年龄不合法,请重新输入!");
            }else {
                this.age = age;
            }
        }
    }
    ---*---
    演示类,非标准类
    
    public class TestClass {
        public static void main(String[] args) {
            //通过 new 关键字创建了一个Dog对象,并把对象的引用赋值给了Dog类型变量 d
            Dog d = new Dog();
            //通过公共的setAge方法设置年龄属性
            d.setAge(56);
            System.out.println(d.getAge() + "岁");
            d.setAge(6);
            System.out.println(d.getAge() + "岁");
        }
    }
    ---*---
    输出结果:
    输入年龄不合法,请重新输入!
    0(成员变量是有初始值的)
    6
  • setAge()方法怎么出现了两个age
    这时又出现了一个问题,在setAge()方法中怎么出现了两个 age 呢,自己赋值给自己吗?这里引出一个关键字 this ,this关键字代表当前类实例。方法中的 this.age 等价于 Dog.age。所以这里的 this.age = age; 是局部变量赋值给成员变量,它并不是自己赋值给自己。


构造方法

  • 分析理解
    先来看一下创建Dog对象的那个语句:

    Dog d = new Dog(); //我们把它分成 “=” 号左边和右边来分析.

    左边:Dog d ,数据类型,变量名。
    右边:new Dog(); 关键字new ,一个类名跟一个()(圆括号)。这其实就是一个方法,一个特殊的方法,而且Java 中的每个类都有一个默认的这种特殊方法 – (构造方法)

  • 构造方法格式:
    public class 类名{
        修饰符 类名 (参数){
        }

    }

    public class Dog {
        //age属性私有化
        private int age;
        //无参构造方法
        public Dog() {
        System.out.println("无参构造方法被调用!");
        }
    }
    ---*---
    演示类,非标准类
    
    public class TestClass {
    	public static void main(String[] args) {
            //只创建一个对象
            Dog d = new Dog();
        }
    }
    ---*---
    输出结果:
    无参构造方法被调用!
    

    根据输出结果可以看出构造方法是在对象创建的时候被调用的,或者说创建对象就一定会调用构造方法。

  • 有什么用:
    一般情况构造方法是用来初始化对象的,我们既然有无参构造方法,那一定就有带参构造方法。

    1. 用法一: 创建对象时给属性赋值

      public class Dog {
          private int age;
          //带参构造方法
          public Dog(int age) {
              this.age = age;
          }
      }
      ---*---
      演示类,非标准类
      
      public class Demo {
          public static void main(String[] args) {
              Dog d = new Dog(6); //调用带参构造赋值age
              System.out.println(d.getAge());//为了整洁隐藏了get/set方法
          }
      }
      ---*---
      输出结果:
      6
      
    2. 用法二: 构造方法调用另一个构造方法

      public class Dog {
          private int age;
      
          //无参构造方法
          public Dog() {
              this(1);  //调用带参构造方法
          }
          //带参构造方法
          public Dog(int age) {
              this.age = age;
          }
      }
      ---*---
      演示类,非标准类
      
      public class Demo {
          public static void main(String[] args) {
              Dog d = new Dog();
              System.out.println(d.getAge());//为了整洁隐藏了get/set方法
          }
      }
      ---*---
      输出结果:
      1
      

      根据输出结果可以看出,创建对象调用了无参构造方法,无参构造方法通过 this(1); 调用了带参构造方法,传递参数1。最后带参构造方法给属性age赋值为1。

  • 为什么创建对象一定要调用构造方法 (涉及继承)
    因为成员变量必须初始化才能使用,构造方法就是用来初始化成员变量的,即使是无参构造。下面来看看当一个对象被创建时,初始化是以怎样的顺序完成的:

    1.设置成员的值为缺省的初始值 (0, false, null)
    2.调用对象的构造方法 (但是还没有执行构造方法体)
    3.调用父类的构造方法
    4.使用初始化程序和初始块,初始化成员
    5.执行构造方法体

    //父类
    class A {
        int a = k();
        //A类构造方法
        A() {
            System.out.println("A类无参构造执行");
        }
        int k(){
            System.out.println("A类K()方法执行");
            return 2;
        }
    }
    //子类
    class B extends A {
        int i = f();
        int j;
    
        {
            j = 37;
            System.out.println("B类初始块被执行");
        }
        //B类构造方法
        B() {
            System.out.println("B类无参构造执行");
        }
        int f() {
            System.out.println("B类f()方法执行");
            return 47;
        }
    }
    //测试类
    public class Demo {
        public static void main(String args[]) {
            B b = new B();
        }
    }
    ---*---
    输出结果:
    AK()方法执行
    A类无参构造执行
    Bf()方法执行
    B类初始块被执行
    B类无参构造执行
    

    流程:所有成员变量设置默认值(0,false,null) --> B类无参开始 --> A类无参开始 --> 赋值a变量执行K()方法 --> A类无参构造执行 --> 赋值i变量执行f()方法 --> 执行B类初始块 --> B类无参构造执行

  • 总结:
    1.构造方法名必须和类名相同
    2.返回值位置什么都不要写 (实际会返回该对象的引用)
    3.定义了带参构造方法,要用无参构造方法时,必须手动定义无参构造方法。
    4.构造方法只能和new关键字结合使用
    5.如果构造方法写了返回值或者void,则被当做普通方法看待
    6.创建对象就会调用构造方法。如果有继承关系,子类构造方法第一行代码就会调用父类构造方法。


一个标准类

package testDemo03;

public class Dog {
	//属性私有
    private int age;
    private String name;
    //给出无参构造和全参构造方法
    public Dog() {
    }
    public Dog(int age, String name) {
        this.age = age;
        this.name = name;
    }
    
    //属性的 get/set 方法
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //其他成员方法
    void eat(){}
}
---*---
标准类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值