Java面向对象:类与对象

一、类

类是封装对象的属性和行为的载体,在Java语言中对象的属性以成员变量的形式存在,而对象的方法以成员方法的形式存在。

1. 类的构造方法

构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的,构造方法分为有参构造方法和无参构造方法,区别就在于有没有参数。说这么多概念是不是感觉有点麻木,直接看下面的例子吧。

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
 1 public class Example { 2    
 3     public Example()  {                              // 定义无参构造方法
 4         System.out.println("无参构造方法"); 
 5     }
 6     
 7     public Example(String name) {                   // 定义有参构造方法
 8         System.out.println("有参构造方法");
 9 } 10 
11 } 
       </pre>

在定义构造方法时,构造方法没有返回值,且构造方法不需要void关键字进行修饰。“public”是构造方法的修饰符,“Example”是构造方法的名称。

在构造方法中可以为成员变量赋值,这样当实例化一个本类的对象时,相应的成员变量也将被初始化。

2. 类的主方法

主方法其实我们已经见过很多次了,Java编译器通过主方法来执行程序,是类的入口点,语法格式如下:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; important; font-size: 12px !important;">
public static void main(String[] args) { 
// ...
}
       </pre>

“static”是指主方法是静态的,若在其中调用其它方法,则该方法也必须是静态的;”void”是指主方法没有返回值;“String[] args”是指主方法的形参为数组,用args[0]~args[n]分别表示程序的第一到第n个参数,可以使用args.length获取参数的个数。

3. 成员变量

对象的属性称为成员变量,也可称为属性。下面以学生类(可比作学生证)举个例子:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;"> 
1 public class Student { 2     private int id;                    // 定义一个int型成员变量,学号
 3     private String name;            // 定义一个String型成员变量, 姓名
 4     
 5     public Student() {                // 定义无参构造方法
 6         
 7     }
 8     public Student(int id, String name) {    // 定义有参构造方法
 9         this.id = id; 10         this.name = name; 11 } 12     
13     public void setName(String name) {            // 定义一个setName()方法,用于导入学生姓名
14         this.name = name;                    // 将参数值赋给成员变量
15 } 16     public String getName() {        // 定义一个getName()方法,用于获取学生姓名
17         return this.name; 18 } 19     
20     public Student getStudent() {        // 返回Student类引用
21         return this; 22 } 23 }
       </pre>

这就是个比较全的例子了,在Java语言中使用class关键字来定义类,Student是类的名称;在Student类中定义了三个成员变量,分别为学号和姓名,可设置初始值也可不设置初始值,若不设置初始值则会有默认值;private关键字用于定义一个私有成员,后面会介绍public、protected和private。接下来的两个构造方法上面已经提到过了,this关键字用于引用对象的成员变量和方法,在后面会有所介绍。一般在这样的类中每一个变量都会有set和get方法,set方法是带参数的方法没有返回值,get方法是有返回值的方法,用于获取。最后还有一个getStudent()方法,它的类型是Student类的,用于返回Student类的引用,用this关键字实现。

4. 成员方法

成员方法对应类的行为,就是上述实例中的getName()和setName()方法,分别为获取学生姓名和设置学生姓名的方法,语法格式如下:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
权限修饰符 返回值类型 方法名(参数类型 参数名){ // ...
    return 返回值;
}
      </pre>

若无返回值,返回值类型用void关键字表示,如上述setName()方法。若有返回值,返回值类型要与方法返回值类型一致。

5. 局部变量

如果在成员方法中定义一个变量,那么这个变量别称为局部变量。例如在上述Student类中的getName()方法中定义一个局部变量id如下:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
public String getName() { int id = 0;                        // 定义一个局部变量
    return id + this.name;
}
     </pre>

局部变量是在方法执行时创建,在方法执行结束时被销毁,使用时必须赋值或初始化。所以局部变量的有效范围从该变量的声明开始到该变量的结束为止

若一个方法中含有与成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行访问。例如id,在上述方法中id=0,而不是Student类中的成员变量id的值。

6. 静态变量、常量和方法

由static修饰的变量、常量和方法被称作静态变量、常量和方法。静态成员是属于类所有的,区别于个别对象,可以在本类或其他类中使用类名和“.”运算符调用,这个在之前的篇幅中的例子也出现过,语法格式为: 类名.静态类成员 。

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;"> 
1 public class StaticTest { 
2     final static double PI = 3.1415926;        // 在类中定义静态常量
3     static int id;                        // 在类中定义静态变量
4     
5     public static void demo01() { 
6         System.out.println("test");
7     }
8     public static void main(String[] args) { 
9         System.out.println(StaticTest.PI);        // 调用静态常量
10         System.out.println(StaticTest.id);        // 调用静态变量
11         StaticTest.demo01();                    // 调用静态方法
12 } 
13     
14 }      </pre>

7. 权限修饰符

Java中的权限修饰符主要包括private、public和protected,这些修饰符控制着对类和类的成员变量以及成员方法的访问。区别见下表:

访问位置 类修饰符
private protected public
本类 可见 可见 可见
同包其他类或子类 不可见 可见 可见
其他包的类或子类 不可见 不可见 可见

若一个类的访问权限为不可见,这个类将隐藏其内的所有数据,以免用户直接访问它。当声明类时不使用public、protected或private修饰符设置类的权限,则这个类预设为包存取范围,即只有同一个包中的类可以调用这个类的成员变量或成员方法。

要特别注意以下情况,在项目中com.adamjwh包下创建AnyClass类,该类使用默认权限时:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
package com.adamjwh; class AnyClass {
 public void doString() {
 // ...
      }
         }
</pre>

此时,即使AnyClass类中的doString()方法又被设置成public访问权限,其访问权限也与AnyClass类的访问权限相同。因为Java规定,类的权限设定会约束类的成员上的权限设定,所以上述代码等同于下面的代码:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; important; font-size: 12px !important;">
package com.adamjwh; 
class AnyClass { 
void doString() { 
// ...
    }
        }
    </pre>

8. this关键字

在Java中,this关键字被隐式地用于引用对象的成员变量和方法,如前面“成员变量”中的例子:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
public void setName(String name) {           
 // 定义一个setName()方法,用于导入学生姓名
    this.name = name;                    
// 将参数值赋给成员变量
    }
</pre>

setName()方法中,this.name指定的就是Student类中name变量,而“this.name=name”语句中第二个name则指定的是形参name。实质上,setName()方法实现的功能就是将形参name的值赋予成员变量name。

this除了可以调用成员变量或成员方法之外,还可以作为方法的返回值。如前面“成员变量”中的例子:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
public Student getStudent() {        
// 返回Student类引用
    return this;
}</pre>

在getStudent()方法中,方法的返回值为Student类,所以方法体中使用return this这种形式将Student类的对象进行返回。

二、对象

Java是面向对象的程序设计语言,对象是由类抽象出来的,所有的问题都是通过对象来处理,对象可以操作类的基本属性和方法解决相应的问题。

1. 对象的创建

在Java中可以使用new操作符调用构造方法创建对象,语法格式如下:

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
Test test = new Test();
Test test = new Test("a");
</pre>

test对象被创建出来时,test对象就是一个对象的引用,这个引用在内存中为对象分配了存储空间,可以在构造方法中初始化成员变量,当创建对象时,自动调用构造方法。

在Java中对象和实例事实上可以通用,下面看一个创建对象的实例。

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">
public class CreateObject {
 public CreateObject() {        // 构造方法
        System.out.println("test");
    } 
public static void main(String[] args) { 
new CreateObject();        // 创建对象
</pre>

在上述实例的主方法中使用new操作符创建对象,在创建对象的同时,自动调用构造方法中的代码。

2. 访问对象的属性和行为

当用户使用new操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。话不多说,直接上代码。

<pre style="margin: 0px; padding: 0px; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;"> 
1 public class ObjectTest {
2 
3     int i = 2018;        // 成员变量
4     public void call() {    // 成员方法
5         for(i=0; i<3; i++) {
6             System.out.print(i + " ");
7             if(i == 2 ) { 
8                 System.out.println();        // 换行
9 } 
10 } 
11 } 
12     
13     public ObjectTest() {        // 构造方法
14 } 
15     
16     public static void main(String[] args) { 17         ObjectTest o1 = new ObjectTest();        // 创建一个对象
18         ObjectTest o2 = new ObjectTest();        // 创建另一个对象
19         o2.i = 60;        // 给第二个类成员变量赋值
20         
21         System.out.println("第一个实例对象调用变量i的结果为:"+ o1.i); 
22 o1.call(); 
23         System.out.println("第二个实例对象调用变量i的结果为:"+ o2.i); 
24 o2.call(); 
25 } 
26 
27 }
</pre>

运行结果如下:

这里我们可以看到,虽然使用两个对象调用同一个成员变量,结果却不相同,因为在打印这个成员变量的值之前将该值重新赋值为60,但在赋值时使用的是第二个对象o2调用的成员变量,所以在第一个对象o1调用成员变量打印该值时仍然是成员变量的初始值。所以两个对象的产生是相互独立的。

如果希望成员变量不被其中任何一个对象改变,可以使用static关键字,也即改第三行代码为 static int i = 2018; ,运行结果如下:

这里由于第19行代码“o2.i=60;”改变了静态成员变量的值,所以使对象o1调用成员变量的值也变为了60;当“o1.i”执行完后,再次调用call()方法,使i的值又重新赋值为0,循环打印,最后i为3,退出循环,所以对象o2调用成员变量的值变成了3。

3. 对象的引用、比较和销毁

对象引用的语法格式为: 类名 引用对象名称 ,例如一个Student类的引用可以为: Student student; ,引用与对象相关联的语法为: Student student = new Student(); .

对象的比较有“==”运算符和equals()方法两种,区别在上一篇中已经介绍过了。equals()方法是String类中的方法,用于比较两个对象引用所指的内容是否相等;而“==”运算符比较的是两个对象引用的地址是否相等。

对象的销毁利用的是Java中的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的占用内存的资源。会被Java虚拟机视为垃圾的对象主要包括以下两种情况:

(1) 对象引用超过其作用范围;

(2) 将对象赋值为null;

虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象。所以Java中提供了一个finalize()方法,如果用户在类中定义了finalize()方法,在垃圾回收时首先调用该方法,并且在下一次垃圾回收动作发生时,才能真正的回收对象占有的内存。由于垃圾回收不受人为控制,Java还提供了System.gc()方法强制启动垃圾回收器,作用是告知垃圾回收器来清理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容