当前位置:   article > 正文

详解 类和对象

类和对象

类和对象

面向 对象与面向 过程


在本章开始 前: 先思考一下 :

什么是面向对象?

看名字它是注重对象的。当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象
赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。

换一个说法: 面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来

补充:

Java是一门纯面向对象的语言(Object Oriented Program,继承OOP),在面向

对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠象

之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物

的认知,对于大型程序的设计、扩展以及维护都非常友好


下面再来一个问题:

什么是面向 过程?

从名字可以看出它是注重过程的。当解决一个问题的时候,面向过程会把事情拆分成: 一个个函数和数据(用于方法的参数) 。然后按照一定的顺序,执行

完这些方法(每个方法看作一个过程),等方法执行完了,事情就搞定了。

换一个说法: 面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。

这里 : C语言就是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

下面我们通过 例子来 区分一下啥是 面下对象,啥是 面向过程。

这里 就来 举一个例子 :

洗衣机里面放有脏衣服,怎么洗干净?

面向过程的解决方法:

1、执行加洗衣粉方法;

2、执行加水方法;

3、执行洗衣服方法;

4、执行清洗方法;

5、 执行烘干方法;

以上就是将解决这个问题的过程拆成一个个方法(是没有对象去调用的),通过一个个方法的执行来解决问题。

面向对象的解决方法:

1、我先弄出两个对象:“洗衣机”对象和“人”对象

2、针对对象“洗衣机”加入一些属性和方法:“洗衣服方法”“清洗方法”、“烘干方法”

3、针对对象“人”加入属性和方法:“加洗衣粉方法”、“加水方法”

4、然后执行

人.加洗衣粉

人.加水

洗衣机.洗衣服

洗衣机.清洗

洗衣机.烘干

解决同一个问题 ,面向对象编程就是先抽象出对象,然后用对象执行方法的方式解决问题。

例子二 : 打麻将例子 你 我 他

面向过程: 打麻将 (你,我,他)

---------解决问题 拆成一个动作,把数据丢进去

面向对象: 我.打麻将(你,他) or 你.打麻将(我,他) or 他.打麻将(我,你)

---------解决问题 抽象出对象,对象执行动作 。

注意:面向过程和面相对象并不是一门语言,而是解决问题的方法,没有那个好坏之分,都有其专门的应用场景。

知道了 面向 对象, 那么 对象 从哪里来 ?

比如 上面 的 洗衣服 过程, 洗衣机, 人 这两个 对象 从哪里来呢?

其实 在 java 中 对象 是 从 类 中 创建出来的。

类就是一类对象的统称。对象就是这一类具体化的一个实例

那么下面我们就来 学习一下 类 .

简单的例子:我们做月饼的模子就是一个类,而通过这个模子可以做出月饼,那么在这个例子当中,类就是那个模 子,而月饼就是那个对象,所以月饼就是一个实

体。一个模子可以实例化无数个对象。 总的来说:类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。 声明一个类就是创建一个新的

数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。我们来 看以下简单的声明一个类。


语法:

// 创建类
class ClassName{ 
  field;    // 字段(属性) 或者 成员变量
  method;    // 行为 或者 成员方法
}
  • 1
  • 2
  • 3
  • 4
  • 5


这里:

class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成属性或者类成员变量。

方法主要说明类具有哪些功能,称为类的成员方法。

class Person{
    
    public String name;
    public int age;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6


来看这里 我们 就通过 class 创建 了 一个 类 ,注意: 类名 一般采用大驼峰。

这里 name / age可以 称为 字段 也可以称为 属性 ,还可以 称为 成员变量 (普通成员变量)。
(在类 中 成员变量 有两种 :1.普通成员变量 如 上面 2. 被 s’tatic定义静态成员变量 )

Person 是 人 的 意思,这里我们 定义的 name 和 age 正好 就是我们 每个人 拥有的 属性。

同样 我们定义的 类中 是 可以 添加 方法的 。


class Person {

  public String name;
  public int age;

  public void eat() {
      System.out.println(name + "大口吃饭");
  }

  public void sleep() {
      System.out.println(name + "正在睡觉");
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14


下面我们 就来 练习 一下 : 创建 类 ,以我们更好的掌握

在这里插入图片描述

在这里插入图片描述

注意: 这里 静态 方法 还没 讲到 可以 先 不 完成。

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

小练习完成后我们 来实例化我们的 对象。

实例化对象

之前我们 学习 过 new 他的 作用 就是用来帮我们 实例化对象的也可以说创建 一个 对象。

class Dog {
  //这里 名字 和 颜色 就是 我们 的 成员变量
  public String name; // 名字
  public String color; // 颜色

  // 狗的行为 (方法)
  public void barks() {
      System.out.println(name + "汪汪叫");
  }

  public void wag() {
      System.out.println(name + "摇尾巴");
  }
}

public class Main {

  public static void main(String[] args) {
      Dog dog = new Dog();
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21


这里我们 就 实例 化出 了 一个 dog 对象。当然 我们 也是

可以 实例化多个对象的(有了 模具 , 想要多少个 我们就能

new 多少个,这里要啥 女朋友 有 这么简单就好了)。

下面继续 :

class Dog {
  //这里 名字 和 颜色 就是 我们 的 成员变量
  public String name; // 名字
  public String color; // 颜色

  // 狗的行为 (方法)
  public void barks() {
      System.out.println(name + "汪汪叫");
  }

  public void wag() {
      System.out.println(name + "摇尾巴");
  }
}

public class Main {

  public static void main(String[] args) {
      Dog dog = new Dog();
      Dog dog2 = new Dog();
      Dog dog3 = new Dog();
      Dog dog4 = new Dog();
      Dog dog5 = new Dog();

  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26


对象 有了 ,我们就 需要 通过 对象 去访问 类中的成员变量,这里我们就可以 通过 .点号 来 访问我们的 成员变量。

访问 类的成员变量

语法: 引用(由类定义的变量名). 成员变量名。

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
}

public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.color = "粉色";
        dog.barks();
        dog.wag();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25


这里我们 就 成功访问 了 类中的 成员变量

在这里插入图片描述

如果 这里我们 没有赋值 呢 ?

这里就 将 dog.namedog.color 给注释掉 来 看一下


在这里插入图片描述

可以看到 为 变为了 null, 这里 如果我们没有 给成员变量 赋值,这里 系统就会 赋于 默认值。

来看 这张图 : 这里 就是我们 每个 类型的默认值。

img

下面 继续 :

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        Dog dog2 = new Dog();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21


这里我们 创建 两个 引用 dog1 和 dog2 来 保存我们 对象的 地址。如:

在这里插入图片描述

类 的静态成员变量

刚刚 提到 过 被 static 修饰的变量 为 静态 成员变量,这里 就来 具体 展示 一下。

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;
    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里 就 通过 static 修饰 了 age 这里的 age 就是 静态 成员变量

静态成员变量的 两种访问方式

1.通过 对象 :

在这里插入图片描述

但 这种 写法 编译器 会报 警告 , 一般 不建议 这样 写 。

2.通过类名 :

在这里插入图片描述

静态 成员变量 能够 通过 类名 来 调用 成员属性,那么我们 的 普通成员变量能不能 呢?

在这里插入图片描述

通过我们的 尝试 发现 他 是 不可以调用 的 ,这里 是为什么呢 ??

这里 就与 之前 提过 一嘴的 方法 区 有关 。

在这里插入图片描述

这里 我们的 静态成员 变量 是 属于类的 ,不是 属于 对象的 ,通过 对象 虽然 可以 访问到 静态成员变量, 但 编译器 会 包 警告 ,这里 我们 就需要通过 方法二 来调用 我们的 静态 成员 变量 。

下面我们 来 做一道 题 来 更 深刻的 理解 一下 静态 成员变量 。

 public class HasStatic {// 1
	private static int x = 100;// 2
	public static void main(String args[]) {// 3
		HasStatic hsl = new HasStatic();// 4
		hsl.x++;// 5
		HasStatic hs2 = new HasStatic();// 6
		hs2.x++;// 7
		hsl = new HasStatic();// 8
		hsl.x++;// 9
		HasStatic.x--;// 10
		System.out.println(" x=" + x);// 11
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13


想一想 这里 的 最终 输出 多少 ,


在这里插入图片描述

静态 成员 变量 你 会了 ,那么 静态成员 方法 也是 同理:


这里只 举例 类名 . 方法名

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;
    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
    public static void Jump(){
        System.out.println("正在跳");
    }

}

public class Main {

    public static void main(String[] args) {
        Dog.age = 10;
        System.out.println(Dog.age);
        Dog.Jump();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29


下面 就来 看 一下 这道题 :

package NowCoder;
class Test {
	public static void hello() {
	    System.out.println("hello");
	}
}
public class MyApplication {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test test=null;
		test.hello();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13


这里 能不能 将 heelo 打印 出来 呢 ?


答案: 这里 是 可以将 hello 打印 出来的 , 还记的我们 静态成员变量 是 放在方法 区 的 吗 ,这里 static 修饰的 是 方法 其实也 是 一样 的 , 同样是 放在 方法区的。


hello方法是一个静态方法,调用静态方法不需要创建实例对象。


此时的 Test test=null; 表示test这个引用不指向任何对象。所以此处可以正常访问。


但是我们需要牢记,静态方法的正确访问方式应该是用过类型来访问。即:Test.hello();

另外 : 在 静态成员变量中 我们 需要 注意一些 事项

如:

1.普通方法中 定义 静态成员变量


这里还是 拿 Dog 这个 类 举例 ,我们 创建 一个 fun方法 ,在 fun方法 中 创建 一个 静态 成员 变量 size.


class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;
    // 狗的行为 (方法)
    public void barks() {
        System.out.println(name + "汪汪叫");
    }

    public void wag() {
        System.out.println(name + "摇尾巴");
    }
    public static void Jump(){
        System.out.println("正在跳");
    }
    
    //注意:  
    public void fun(){
        public static int size = 10;
    }

}

public class Main {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30


在这里插入图片描述

可以 发现 这里报错 了, 其实 很容易 理解 。

1.被static 修饰的是属于类的,这样定义就不是属于类属于方法了

2.假设能定义 fun方法的调用需要 对象的引用来调用 如果可以定义static 的变量, 这个变量不需要对象 通过类名 Person 就可以调用

2.静态成员方法 调定义 静态成员 变量


那么 我们 在 一个 静态 的方法中 定义 一个 静态的 变量 呢?

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;

    public static void Jump(){
        System.out.println("正在跳");
    }
    
    public static void func(){
        public static int size = 10;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述


这里 虽然 不需要 对象 了 但是 被static 修饰的是属于类的,这样定义就不是属于类属于方法了

这里 不能 在 方法 中 创建 静态成员变量,那么我们 调用 方法 总可以了 吧 ,下面我们 就来 看一下 。

3普通方法 调用静态 方法

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;
    // 狗的行为 (方法)
  
    public static void func(){
        System.out.println("测试 的 静态 方法");
    }
    public void func2(){
        func();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

可以看到 我们 在 普通 成员 方法 中 调用 静态 成员方法 编译器 没有 报错 , 其实 也 不难 想 。

普通方法需要对象,静态方法不需要对象 ,方法两部分不干扰,所以可以调用 如果在静态方法中调用普通呢?

如: 旅游 , 有对象的(普通成员 方法) 是不是 都会带 自己 的 女朋友 去, 如果 自己 一个人 偷偷 去 ,回来 不得 被 女朋友 提 分手 ,而 一个 单身狗(静态成员方法)是不是 可以 带 人 (有好感的 妹子 ) 去 , 或者 一个 人去 这 都 是 可以 的 。

同理 这 里 普通 成员 方法 都能 调用静态 方法 , 那么 在 静态方法 中 调用 静态 方法 同样 也是 可以的 。

在这里插入图片描述

普通 方法 能够 调用 静态方法, 那么 我们 静态 方法 能不能 调用 一个 普通方法 呢 ???

4.静态方法调用 普通方法

class Dog {
    //这里 名字 和 颜色 就是 我们 的 成员变量
    public String name; // 名字
    public String color; // 颜色

    // 静态成员变量
    public static int age;

    public static void func1(){
        func2();
        System.out.println("func1 :: 测试");
    }
    public void func2(){
        System.out.println("func2 :: 测试");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述


可以 发现 这里 报错 了 , 为什么 呢?

想一想 其实非常简单, 我们知道静态方法是不需要对象的,而普通方法是需要对象 将一个需要对象的 放进一个没有对象的那肯定会发生错误的。

举例: 还是 拿 旅游 举例 , 一个 没有 对象的 人 叫 一个 有对象的 人 去 旅游 , 但是 有一个 条件 不能 带女朋友 , (我 自己 都没

有,不能让你带来 让我吃 狗粮 ) 如果 这个 人 去 了 那么 旅游 回来 ,女朋友百分之 百 会 提出 分手 (旅游 都 不带我 ,你肯定 是 不 爱

我 ),这时 肯定是 不能 去 的 吗 (相比 一个人 旅游 还不如 和 女朋友 在一起 )。

那么 这 不就 一个 道理,在 没有 对象的 方法 中 调用 需要对象的 方法 拿肯定是 不行 的 。

如果非要 在 静态 方法中 调用 不同 方法 其实 也 非常简单 , 这里 还是 旅游 举例 , 这里 就 直接 拉上 对象 不就 可以 了 吗 。

代码 这样写 :

在这里插入图片描述

静态 方法 中 没有对象我们创建 一个 对象 来 使用。

这里 普通 成员变量 和 静态 成员 变量 就 讲完了 ,下面 来 画个 图 形象的 体现 一下 两者之间的关系。

img


这里 补充 :

在 类中 定义的变量 是可以 被 fine 修饰 的

class Student{
    public final int SIZE = 10;
    public static final int SIZE2 = 20;
}
  • 1
  • 2
  • 3
  • 4

final修饰的叫常量,也属于对象。 被final 修饰,后续不可更改 同样 final 也是 可以修饰 静态变量为静态的常量,属于类本身,只有一份 被final修饰,后续不可更该 另外一个变量存放在哪里和你是否被fine修改无关


注意: 常量 一般 使用 大写


看完 静态 成员 变量下面我们 来学习一下 构造方法 ,

构造方法

1.初始化 对象


通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败

public static void main(String[] args) {
  int a;
  System.out.println(a);
}
// Error:(26, 28) java: 可能尚未初始化变量a
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

要让上述代码通过编译,非常简单,只需在正式使用a之前,给a设置一个初始值即可。如果是对象:

在这里插入图片描述

那么 如何 初始 化对象 呢 ?

class Dog {
    public String name;
    public int age;    
}


public class Main {


    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "旺财";
        dog.age = 10;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

可以看到 我们 这里 成员 变量 就 2 个 初始 化 直接 通过 dog. 即可 ,如果 成员 变量 一多 是不是 就 不太方便 ,那么 对象 要如何初始化呢?

这里 在 来 一个问题 : 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?

怀着 这 两个 问题 来 看一下我们的 构造方法。

构造方法

概念:构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

另外 : 在对对象产生(对象实例化/ new 的执行 过程 ) 会有两个 步骤 。

1.为对象分配内存空间

2.调用合适的构造方法 (一个 类 中可以 拥有 多个 构造方法 ,如: 不带 参数 带 参数 (这个 参数 又会 有 个数 区别) 这里 就 构成 了 重载)

当 这 2 个 步骤 走完 才会真正的 创建 对象。

下面 就来 演示 一下 :

class Dog {
    public String name;
    public int age;
    
    public Dog(){
        System.out.println("不带参数的 构造方法");
    }
    public Dog(String name){
        this.name = name;
        System.out.println("带有 一个 参数的构造 方法");
    }
    public Dog(String name, int age){
        this.name = name;
        this.age = age;
        System.out.println("带有 两个 参数的 构造 方法");
    }

}
public class Main {


    public static void main(String[] args) {
        Dog dog1 = new Dog();
        Dog dog2 = new Dog("旺财");
        Dog dog3 = new Dog("小黑", 14);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在这里插入图片描述

可以看到我们 就 创建 出 3 个 构造 方法 。 这里 的 构造 方法 也 是 可以 被 private 修饰 的 , 此时 其他 的 类 就无法 通过 new 这个 构成方法 来 创建 对象。

另外 : 当然 构造方法 所处类的内部是可以被调用的,因为 private 就是 将 所修饰部分 私有化,只有内部才能使用。外者不能使用既然 构造方法 可以私有化,肯定由它的作用: 实现 单例模式 的 大前提,现在不讲,还不会

这里 大家 会不会 有一个 疑问 ? 为啥 一开始 没写 构造 方法 不是 一样 创建 出对象 。

其实 如果 我们没有写 构造 方法 ,我们的 编译器 会 默认 创建 一个 不带 参数的 构造 方法。

class Dog {
    public String name;
    public int age;

//    public Dog() {
//        System.out.println("不带参数的 构造方法");
//    }
//
//    public Dog(String name) {
//        this.name = name;
//        System.out.println("带有 一个 参数的构造 方法");
//    }
//
//    public Dog(String name, int age) {
//        this.name = name;
//        this.age = age;
//        System.out.println("带有 两个 参数的 构造 方法");
//    }

}

public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27


这里 就 先 将 我们 创建 的 构造 方法 屏蔽 掉 我们 执行 下 看看 。

在这里插入图片描述

这里 就 是 成功 执行 了 程序 。

注意 : 如果我们 在类中 写 了 构造 方法 ,编译器 就不会 会默认 提供 不带参数的 构造 方法了。

还是 这个 代码 : 我们 将 不带 参数 的 构造 方法 注释 掉

class Dog {
    public String name;
    public int age;

//    public Dog() {
//        System.out.println("不带参数的 构造方法");
//    }

    public Dog(String name) {
        this.name = name;
        System.out.println("带有 一个 参数的构造 方法");
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("带有 两个 参数的 构造 方法");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

可以 看到 报错 了 。

另外 : 构造方法支持重载. 规则和普通方法的重载一致 构造方法重载规则:类名相同,参数的类型和个数,两者中,至少有一个不同项。调用构造方法时,编译器会自动筛选调用合适的构造方法

构成方法 了解 完我们 来 了解 一下 this

this

关于 this 我们 有 三种 用法 ,这里 就先 罗列 出来

1.this.data 调用当前的对象的 属性/字段/成员变量

2.this.func() 调用当前的对象的方法

3.this()调用当前对象的其他构造方法

1.this.data

1.this.data 调用当前的对象的 属性/字段/成员变量

这个 this.data 是 用来 解决 形参名不小心与成员变量名相同的 问题 。

先来 看一下 同名 不适用 this 的 情况

class Dog {
    public String name;
    public int age;

    public Dog() {
        System.out.println("不带参数的 构造方法");
    }

    public Dog(String name) {
        this.name = name;
        System.out.println("带有 一个 参数的构造 方法");
    }

    public Dog(String name, int age) {
        name = name;
         age = age;
        System.out.println("带有 两个 参数的 构造 方法");
    }

    public void sleep() {

        System.out.println(age + "岁的 小狗");
        System.out.println(name + "正在睡觉");
    }

}

public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog("小黑",4);
        dog.sleep();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34


这里就 通过带有 两个 参数 的 构造 方法 ,对 age 和 那么 赋值 ,然后 条用 sleep() 方法 ,来 看 赋值情况

在这里插入图片描述

这里 看到 我们 的 age 为 0 ,name 为 null , 这里 是 为什么呢 ???

其实 这里 有点 与 c 中 的 局部 变量 优先 一样 ,

这里 传入 的 形参 名 age 和 name 与 赋值 的 名字 相同 , 编译器 ,并不知情 ,会按照 局部变量 优先 , 此时 就会出现 自己 赋值 给 自己 的 情况

这里 就可以 使用 我们 的 this 来 指定 当前变量是 这个 类中 的 。

   public Dog(String name, int age) {
        this.name = name;
         this.age = age;
        System.out.println("带有 两个 参数的 构造 方法");
    }

    public void sleep() {

        System.out.println(age + "岁的 小狗");
        System.out.println(name + "正在睡觉");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述


第一种用法 看完 我们 来 看 第二种

2.this.func()


2.this.func() 调用当前的对象的方法

class Dog {
    public String name;
    public int age;

    public void eat() {
        System.out.println(name + "开心的 吃");
    }

    public void sleep(String name) {
        this.name = name;
        this.eat();
        System.out.println(name + "正在睡觉");
    }
}

public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sleep("小黑");
    }    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

这里 就 通过`` this.方法名 ` 调用 了 eat 方法 。

3.this()


3.this()调用当前对象的其他构造方法

注意: 这里 this() , 括号 内 是 可以带参数的 参数 类型 与 参数个数决定 所调用 的 构造方法,另外 这里 this() 只能使用在 构造方法 当中 ,而且 只能 在 第一行 。

下面 演示 :


class Dog {
    public String name;
    public int age;

    public Dog() {
        // 调用 带有 两个 参数  的 构造 方法
        this("小黑", 15);
        System.out.println("不带参数的 构造方法");
    }

    public Dog(String name) {
        // 调用 不带参数的 构造 方法
        this();
        this.name = name;
        System.out.println("带有 一个 参数的构造 方法");
    }

    public Dog(String name, int age) {
        this.name = name;
         this.age = age;
        System.out.println("带有 两个 参数的 构造 方法");
    }

    public void sleep() {

        System.out.println(age + "岁的 小狗");
        System.out.println(name + "正在睡觉");
    }
}
public class Main {

    public static void main(String[] args) {
        Dog dog = new Dog();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

在这里插入图片描述


另外 :

在这里插入图片描述

这样 使用 this.() 是 不可以的 , 进入 不带参数 的 构造方法 , 然后 通过``this.(“小黑”) 进入 带有一个 参数的 构造方法 , 然后 又 通过this.()`

绕回 来 了 ,这里 就会 死循环 , 显然 是 不可以的 ,这里我们的编译器 ,就 比较 智能 直接报错 了 。

下面 就 进入 到 本文 的 最后一讲 代码 块 。

代码块

概念:

使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:

普通代码块(本地代码块)

构造块(实例代码块)

静态块 (静态代码块)

同步代码块(后续讲解多线程部分再谈)

这里主要 讲 实例代码块 和 静态 代码 块

1.本地 代码块

public class Main {

    public static void main(String[] args) {
        { //直接使用{}定义,普通方法块
            int x = 10;
            System.out.println("x1 = " + x);
        }
        int x = 100;
        System.out.println("x2 = " + x);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行结果 为 10 和 100.

这种 代码块 用 的比较少 ,下面 就来 看我们的 实例 代码块

2.实例代码块

构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。

class Dog {
    public String name;
    public int age;

// 这里 就是 实例 代码块
    {
        name = "小黑";
        age = 20;
    }

    public void eat() {
        System.out.println(name + "大口的吃");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述


这里 就通过 实例代码 块 初始化 了 实例 成员变量 。

3.静态代码块

使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。

class Dog {
    // 姓名
    public String name;
    // 年龄
    public int age;
    // 颜色
    public static  String color;
    // 性格
    public static String character;

    实例代码 块
    {
        this.name = "小黑";
        this.age = 20;
    }

    静态 代码 块
    static {
        color = "粉色";
        character = "乖巧";
    }
    public void eat() {
        System.out.println(name + "大口的吃");
    }
    public void fun(){
        System.out.println(name + " 真是 " + character + "的 狗 "+ "颜色 是" + color);
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
        dog.fun();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36


最终 我们的 结果 :

在这里插入图片描述

最后我们 来 看一下 实例 代码 块 和 静态 代码 块 的 区别

实例代码块 or 静态 代码块

下面 就来 看代码 分析 :

class Dog {
    private String name;
    public int age;

    public void func(){
        System.out.println("这是  测试 方法");
    }

    {
        System.out.println("小灰灰");
    }

    static {
        System.out.println("红 太郎 ");
    }

    static {
        System.out.println("灰太狼");
    }
}

public class Main{
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.func();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27


想一想 这里 我们 会 输出 什么:

在这里插入图片描述

可以看到 我们 会先 输出 静态 代码 块里的 内容 然后 是 实例代码 块 ,最后 是 我们的 方法 。

通过 上面我们 能 总结 出 一种 规律 (这里 只 给出 了 一组 测试 用例 , 如果 你 多尝试 几次 也 是 这样 的 )

结论: 当 一个类 中 既有 静态 代码块 和 实例 代码块,和 方法时 ,会先调用 静态 代码块 ,然后是 实例 代码 块 ,最后是 方法


class Dog {
    private String name;
    public int age;

    public void func(){
        System.out.println("这是  测试 方法");
    }

    {
        System.out.println("小灰灰");
    }

    static {
        System.out.println("红 太郎 ");
    }

    static {
        System.out.println("灰太狼");
    }
}

public class Main{
    public static void main(String[] args) {
        Dog dog = new Dog();
//        dog.func();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28


这里我们 讲 调用 的 方法 注释 掉 , 来看一下 结果 。

在这里插入图片描述

可以看到 还是 我们的 静态 代码块 先 执行 ,然后 是 实例 ,这里 没有 通过 对象 调用 fun 方法 ,所以 fun 没有 生效。

另外 : 静态 代码 块只能 执行 一次

class Dog {
    private String name;
    public int age;

    public void func(){
        System.out.println("这是  测试 方法");
    }

    {
        System.out.println("小灰灰");
    }

    static {
        System.out.println("红 太郎 ");
    }

    static {
        System.out.println("灰太狼");
    }
}

public class Main{
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.func();
        Dog dog2 =new Dog();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在这里插入图片描述

来 看 我们 再 new 了 一个 对象 时 , 这里 静态代码 块 中 的 红太郎 和 灰太狼 就 没有 了 。

总结 :

静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。

静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行

最后 我们 再来 思考 一个 问题 静态 代码块 ,和 静态 成员 变量 是那个 先执行 呢 ??


下面 我们 就 来 通过 代码 来看 一下 。

class Dog {
    private String name;
    public int age;

    public static int count = 10;
    
    count 
    public void func(){
        System.out.println("这是  测试 方法");
    }

    {
        System.out.println("小灰灰");
    }

    static {
        count = 20;
        System.out.println("红 太郎 ");
    }

    static {
        System.out.println("灰太狼");
    }
}

public class Main{

    public static void main(String[] args) {
        System.out.println(Dog.count);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31


想一下 这里的 count 输出 多少 。

在这里插入图片描述

这里 我们 直接 通过 类名 调用 count 发现 count 等于 10 ,可以 发现 这里 是 先 执行 了 public static int count = 10;再执行 了 静态 代码块中 的

count = 20;

那么我们 调换 一下 位置 再来看一下 。

class Dog {
    private String name;
    public int age;

   
    
    public void func(){
        System.out.println("这是  测试 方法");
    }

    {
        System.out.println("小灰灰");
    }

    static {
        count = 20;
        System.out.println("红 太郎 ");
    }

    static {
        System.out.println("灰太狼");
    }
    public static int count = 10;
}

public class Main{

    public static void main(String[] args) {
        System.out.println(Dog.count);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31


此时 count 又等于 多少 呢??

在这里插入图片描述

可以发现 等于 10 这里 是 先 执行 了 代码 块 ,再执行 了 public static int count = 10;

那么 这里 可以得出 结论 , 静态代码 块 与 静态 成员变量的 执行 顺序 与 写 的 顺序 有关 ,谁在前面 谁 先 执行 ,注意 这里 静态代码 块 之间 这时 这样的 。


最后 来 看 一道题目 : 请问 下面 cut 等于几 ??

public class Test{
    static int cnt = 6;
    static{
        cnt += 9;
    }
    public static void main(String[] args){
        System.out.println("cnt = " + cnt);
    }
    static{
        cnt /=3;
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

按照上面总结 的 我们 很容易得出答案 , 如 先 执行 cnt = 6, 然后 再 执行 cnt += 9 最后 再执行 cnt /= 3; 答案 就为 5。

你写 对 了吗??

本文就 到 此为止。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号