什么是类、什么是对象
- 概述
官方定义:
类就是拥有相等功能和相同属性的对象的集合 – 抽象的
对象就是类的实例 – 具体的
个人理解:
类是一个模板,它描述一类对象的行为和状态。- -例如 手机设计图纸
对象则是类所描述的具体的存在,有状态和行为。- -例如 我手中的小米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(); } } ---*--- 输出结果: 无参构造方法被调用!
根据输出结果可以看出构造方法是在对象创建的时候被调用的,或者说创建对象就一定会调用构造方法。
-
有什么用:
一般情况构造方法是用来初始化对象的,我们既然有无参构造方法,那一定就有带参构造方法。-
用法一: 创建对象时给属性赋值
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
-
用法二: 构造方法调用另一个构造方法
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(); } } ---*--- 输出结果: A类K()方法执行 A类无参构造执行 B类f()方法执行 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(){}
}
---*---
标准类