菜鸟话Java---类和对象

类和对象的概念

类(class)是构造对象的模板或蓝图。可以把类比作,而对象比作一本本具体的书,比如课本,小说等。类是抽象的概念,对象是具体的实体。

对象的具体特征

  • 对象的行为 —— 可以对对象施加哪些操作,或可以对对象施加哪些方法
  • 对象的状态 —— 当施加哪些方法时,对象应该任何响应
  • 对象标识 —— 如何辨别具有相同行为而状态不同的对象

封装

封装是将数据和行为组合在一个类中,并对对象的使用者隐藏了数据的实现方式。可以想象你在自动取款机中取钱的情形,你并不知道自动取款机是如何取出你所需要的钱的,你也不需要知道。当自动取款机的取款的原理发生改变时(可能原来的有安全隐患),但你所要做的仍然是输入取款金额,然后取钱。这就是封装的好处。

一个Java的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class People {

public String name;

public int age;

public String adress;

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

public void work(){
System.out.println("工作");
}

}

如上示例是一个表示人的Java类,下面我们来分析这个类:

首先class 类名表示一个类,这个上一篇文章介绍过,不用多说。public是公有的意思,即所以类都看。在这个类中我们定义了两个属性nameage,这个也叫做成员变量。
我们又定义了人的行为sleepwork,这个在Java中叫做方法或函数.

现在我们创建了这个模板,那么怎么创建具体的人的对象,这就要用到new,具体代码如下:

1
2
3
4
5
6
7
public static void main(String[] args) {
People people = new People();//获取对象的引用
people.name = "小明";//对象使用 . 运算符来调用对象的方法或引用成员变量
people.age = 18;
people.sleep();
people.work();
}

Private

下面我们来扩展这个Java类,我们给它再添加一个是否有女朋友的属性,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  public class People {

String name;

int age;

boolean isHaveGirlFriend;

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

public void work(){
System.out.println("工作");
}

}

试想一下,如果你问陌生人是否有女朋友,帅哥还好,要是一个肥仔(比如我)就不想理你;但是你可以直接调用
people.isHaveGirlFriend来看我是否有女朋友,这就有点侵犯隐私了。可是我们怎么限制别人对对象的调用(即把成员变量声明为私有域)
,这就要使用private关键字,private关键字修饰的属性或方法只能再本类中可见,一般所有的成员变量要用private修饰.(之后会详细介绍Java 访问修饰符)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class People {

String name;

int age;

private boolean isHaveGirlFriend;

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

public void work(){
System.out.println("工作");
}

public boolean isHaveGirlFriend() {//通过调用方法来访问属性,可以控制属性的访问,方法名一般取set/get+成员变量名,boolean变量用is+变量名,注意首字母大写
return isHaveGirlFriend;
}

public void setHaveGirlFriend(boolean haveGirlFriend) {
isHaveGirlFriend = haveGirlFriend;
}
}

同理方法用private修饰是私有方法

静态域和静态方法

静态域

有时候我们会想要使用一个概念,而不是一个具体的对象来做一些事情。比如要统计人类的总数,那就必须针对人类这个抽象概念,并且
要有属于这个抽象的变量(如人的总数这个变量),而不是每个对象的成员变量(比如说每个人的年龄,你不能说人类的年龄)。要实现这个
抽象的变量(即静态域),只需添加static关键字

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
public class People {

String name;

int age;

private static int count = 0;//声明一个静态域,表示人类的总数,尽量使用private

private boolean isHaveGirlFriend;

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

public void work(){
System.out.println("工作");
}

public boolean isHaveGirlFriend() {
return isHaveGirlFriend;
}

public static void add(){
count++;
}

public void setHaveGirlFriend(boolean haveGirlFriend) {
isHaveGirlFriend = haveGirlFriend;
}
}

每个对象对于类的成员变量都有自己的拷贝,比如1000个人类对象,就有1000个成员变量name,但是只有一个静态域人类的总数count

注意:静态域只能通过类名.静态域变量名来直接访问,所有也可以称为类域

静态常量

静态常量即可以直接通过类名.常量名直接访问的量,格式如下:

1
public static final int COUNT = 1;

静态方法

静态方法是只能通过类名.静态方法名调用的方法;静态方法的定义和静态域一样,只需要加上一个static即可。

注意:静态方法只能访问类中的静态域,而不是类的成员变量

方法

方法的定义访问修饰符 返回值 方法名(参数类型 参数名 ...){ }

1
2
3
4
5
public void sleep(){System.out.println("睡觉");}//修饰符为public   void表示无返回值  sleep是方法名 System.out.println("睡觉");是方法执行的功能

public String getName(int id){//这是个通过指定参数返回用户姓名的方法 String表示返回参数类型 int id 是方法的参数
return names[id]; // return 关键字表示返回指定参数 names[id]是返回的参数
}

注意:return会结束所在的方法,例如

1
2
3
4
5
6
public void sleep()
{
if (true)
return;//直接退出方法
System.out.println("睡觉");//永远无法访问
}

局部变量

  • 局部变量声明在方法、构造方法或者语句块中;
  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
  • 访问修饰符不能用于局部变量;
  • 局部变量只在声明它的方法、构造方法或者语句块中可见;
  • 局部变量是在栈上分配的。
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

成员变量(实例变量)

  • 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
  • 当一个对象被实例化之后,每个实例变量的值就跟着确定;
  • 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
  • 访问修饰符可以修饰实例变量;
  • 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
  • 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
  • 实例变量可以直接通过变量名访问

重载

如果多个方法有相同的名字,不同的参数,那这多个方法重载。例如:

1
2
3
4
5
6
7
8
9
10
11
public boolean equal(int a,int b){
return a == b;
}

public boolean equal(String a,String b){
return b.equals(a);
}
//这个方法与上面的方法不能重载,由于返回类型不能作为重载判断的方式
public int equal(String a,String b){
return a.compareTo(b);
}

注意:Java允许重载任何方法。因此要完整地描述一个方法,需要指出方法名以及参数类型,这叫做方法
的签名。返回类型不是方法签名的一部分。

构造器

1
2
3
public 类名(参数...){

}

构造器的语法:

  • 构造器与类名相同
  • 每个类可以有一个以上的构造器,如在类中没有显示的声明一个构造器,系统就会提供一个无参数的构造器
  • 构造器可以有0个,1个或多个参数
  • 构造器没有返回值
  • 构造器总是伴随着new操作一起调用
  • 构造器中不能定义与成员变量同名的局部变量

注意:仅当类没有提供任何构造器的时候,系统才会提供一个默认的构造器。如果自己给出了一个构造器,要想使用系统默认的构造器就必须自己
提供一个默认构造器

1
2
3
4
5
6
7
8

public People(){//默认构造器

}

public People(String name){

}

this

this关键字表示这个对象的引用

作用1:引用方法的隐式参数

1
2
3
public People(String name){
this.name = name;//this.name表示成员变量name,name表示构造方法中的name
}

作用2:调用构造器

1
2
3
4
5
6
7
 public People(){//默认构造器
this("无名氏");//调用下面的构造器
}

public People(String name){
this.name = name;
}

对象变量(或引用变量)

我们已经知道People people1 = new People();是获取一个对象的引用;实际上一个对象变量有没有包含一个对象,而仅仅是
引用一个对象。在Java中任何对象变量的值都是对储存在另一个地方的一个对象的引用。new操作符的返回值也是一个引用,如图:

注意:People people;没有引用对象

方法参数

按值调用 : 表示方法接受的是调用者提供的值,Java是按值调用
按引用调用 : 表示方法接受的是调用者提供的变量地址

Java中方法参数的使用情况:

  • 一个方法不能修改一个基本类型的参数
  • 一个方法可以改变一个对象参数的状态
  • 一个方法不能让对象参数引用一个新的对象

在定义一个类时,要给类取名字,类名一般要根据类的作用来取,而不是毫无意义的字符;不过随着定义的类
越来越多,类名很有可能重复。为了解决这个问题,我们就采用包(package)

类的导入

我们使用别的包中的公有类时,我们有两种方式来访问:第一种是通过每个类前面直接添加完整的包名。如:

1
java.time.LocalDate localDate = java.time.LocalDate.now();

第二种是导入类,导入类的关键字import,语法如下

1
2
3
import 包名.类名;//导入单个类

import 包名.*;//导入这个包中所有的文件

例如:

1
2
3
4
import java.time.LocalDate;
...
//之后就可以直接使用LocalDate类了
LocalDate localDate = LocalDate.now();

注意:如果一个类中出现重名的类,编译器无法确定使用哪个;那就必须在每一个(重名的)类名
前面加上完整的包名

静态导入

import不仅可以导入类,还可以导入静态方法和静态域

例如

1
import static java.lang.System.*;//之后就可以直接使用System的静态方法和静态变量

将类放入包中

要想将一个类放入包中,就必须将包的名字放在源文件的开头,包中定义类的代码之前。例如:

1
2
3
4
5
package com.demo.core;

public class People{
...
}

包的作用域

如果类或类中变量,方法没有被privatepublic修饰,那么这个部分(类,方法和变量)可以被同一包中所有方法访问

类设计技巧

  • 一定要保证数据私有
  • 一定要对数据初始化
  • 不要在类中使用过多的基本类型
  • 不是所有的域都需要独立的域访问器和域修改器
  • 将职责过多的类进行分解
  • 类名和方法名要能够体现它们的职责
  • 优先使用不可变的类