《JAVA程序设计与实例》记录与归纳--类与对象

类与对象

概念贴士:

1.  类必须先定义了才能使用。类是创建对象的模板,创建对象也叫类的实例化。

 

2.  在Java中,使用new关键字来创建对象,一般有一下3个步骤:

    1)声   明:声明一个对象,包括对象名称和对象类型。

    2)实例化:使用关键字new创建一个对象。

    3)初始化:使用new创建对象时,会调用构造方法初始化对象。

 

3.  在类实例化的过程中自动执行的方法叫做构造方法,它不需要手动调用。构造方法可以在类实例化的过程中完成一些初始化的工作。构造方法的名称必须与类的名称相同,并且没有返回值。每个类都有构造方法,如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的构造方法。

 

4.  Java通过修饰符来控制类、属性和方法的访问权限和其他功能,通常放在语句的最前端。

 

5.  Java的修饰符很多,分为访问修饰符和非访问修饰符。其中访问修饰符也叫访问控制符,是指能够控制类、成员变量、方法的使用权限的关键字。  在面向对象编程中,访问控制符是一个很重要的概念,可以使用它来保护对类、变量、方法和控制方法的访问。

 

6.  Java支持4种不同的访问权限:

    1)public      共有的,对所有类可见

    2)protected    受保护的,对同一包内的类和所有子类可见

    3)private      私有的,在同一类内可见

    4)默认的      在同一包内可见,默认不使用任何修饰符

 

6.1  public:公有的

    被声明为public的类、方法、构造方法行业接口能够被任何其他类访问。如果几个相互访问的public类分布在不同的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被子类继承。

    例子:public static void main(String[] arguments){}

    PS:Java程序main()方法必须是设置成公有的。

 

6.2  protected:受保护的

    被声明为protected的变量、方法和构造方法能够被同一包中的任意其他类访问,也能够被不同包中的子类访问。protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。

    例子:

 1 public class Dog{
 2     protected void bark(){
 3         System.out.println("汪汪,不要过来!");
 4     }
 5 }
 6 
 7 class Teddy extends Dog{            //泰迪
 8     protected void bark(){
 9         System.out.println("汪汪,我好怕,不要跟着我!");
10     }
11 }

    PS:如果把bark()方法声明为private,那么除了Dog之外的类将不能访问该方法。如果把bark()方法声明为public,那么所有的类都能够访问该方法。如果只想让该方法对其所在类的子类可见,则将该方法声明为protected即可。

 

6.3  private:私有的

    私有访问修饰符是最严格的访问控制级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。  声明为私有访问类型的变量只能通过类中公共的getter/setter方法被外部类访问。private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

    例子:

 1 public class Dog{
 2     private String name;
 3     private int age;
 4     public String getName(){
 5         return name;
 6     }
 7     public void setName(String name){
 8         this.name=name;
 9     }
10     public int getAge(){
11         return age;
12     }
13     public void setAge(int age){
14         this.age=age;
15     }
16 }

    PS:程序中,Dog类中的name、age变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,程序中定义了两对public方法,getName()/setName()和getAge()/setAge(),用来获取和设置私有变量的值。

    PS:this是Java中的一个关键字,在类中定义访问私有变量的方法,习惯上是这样命名的:在变量名称前面添加get或者set,并将变量的首字母大写。上述两对方法由于经常使用,也有特定的称呼,称为getter和setter方法。

 

6.4  默认的:不使用任何关键字

    不适用任何修饰符声明的属性和方法,对同一个包内的类是常见的。接口的变量都隐式声明为public static final(final为非访问修饰符之一),而接口里的方法默认情况下访问权限为public。

 

6.5  访问控制符使用小总结:

  1. 访问控制符可以令我们便于控制代码的权限。

    1)当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为public。

    2)当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。

    3)当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为public、protected或者省略。

  2.  方法继承的规则。

    1)父类中声明为public的方法在子类中也必须为public。

    2)父类中声明为protected的方法在子类中要么声明为protected,要么声明为public,不能声明为private。

    3)父类中默认修饰符声明的方法,能够在子类中声明为private。

    4)父类中声明为private的方法,不能被继承。

 

7.  在Java中,变量的作用域分为4个级别,即类级、对象实例级、方法级和块级。(详见实例3-4)

    1)类级变量又称为全局级变量或者静态变量,需要使用static关键字修饰,类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。

    2)对象实例级变量就是成员变量,实例化后才会分配内存空间,才能访问。

    3)方法级变量是在方法内部定义的变量,是局部变量。

    4)块级变量是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块则变量消失,如if、for语句的块。块是指由大括号(花括号)包围的代码。

 

8.  在Java中,this可以在类里引用这个类的属性和方法。this关键字用来表示当前对象本身,或当前类的一个实例,通过this关键字可以调用本对象的所有方法和属性。(详见实例3-5)

 

9.  成员变量与方法内部的变量重名时,希望在方法内部调用成员变量,可以通过使用this关键字区分同名变量。(详见实例3-6)

 

10.  在构造函数中通过this引用来调用另一个构造函数,也就是相当于调用本类的其他构造方法,它必须作为构造方法的第一句(即作为方法名初始化对象)。(详见实例3-7)

 

11.  需要在某些完全分离的类中调用一个方法,并将当前对象的一个引用作为参数传递时,可以使用this关键字,作为参数传递。(详见实例3-8)

12.  在Java中

,同一个类中的多个方法可以有相同的名字,但参数列表不同,这被称为方法重载(method overloading)。重载是面向对象的一个基本特性。  参数列表又叫参数签名,包括参数的类型,参数的个数与参数的顺序,只要有一个不同就叫做参数列表不同。(详见实例3-9)

 

13.  1.重载说明:

    1)参数列表不同包括:个数不同、类型不同和顺序不同。

    2)仅参数变量名称不同是不可以的(毕竟那只是形参)。

    3)与成员方法一样,构造方法也可以重载。

    4)声明为final的方法不能被重载(感兴趣可以查询final这个非访问修饰符)。

    5)声明为static的方法不能被重载,但是能够被再次声明。

    2.方法的重载规则:

    1)方法名称必须相同。

    2)参数列表必须不同。

    3)方法的返回类型可以不同,也可以相同。

    4)仅仅返回类型不同不足以成为方法的重载。

    3.方法重载的实现:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等逐个去匹配,以选择对应的方法,如果匹配失败,则编译器报错,这叫重载分辨。

 

14.  Java为每种基本数据类型分别设计了对应的类,实现数据间类型转化,这些类被称之为包装类(Wrapper Classes)。

 

15.  封装就是将属性私有化,提供公有的方法访问私有的属性。其实现步骤如下:

    1)修改属性的可见性限制对属性的访问。

    2)为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问。

    3)在赋值和取值方法中,加入对属性的存取限制。

 

16.  为了实现良好的封装性,通常将类的成员变量声明为private,再通过public的方法对这个变量进行访问。对一个变量的操作,一般是读取和赋值操作,下面分别定义两个方法来实现这两种操作,一个是getXxx()方法(Xxx表示要访问的成员变量的名字),用来读取这个成员变量操作;另外一个是setXxx()方法,用来对这个成员变量赋值。(详见实例3-10)

 

 

代码解释:

实例3-1

 1 package duke.example.ch3;
 2 
 3 public class Dog{
 4     String name;                    //名字
 5     int age;                            //年龄
 6 
 7     void bark(){                    //汪汪叫
 8         System.out println("汪汪,不要过来");
 9     }
10 
11     void hungry(){                //饥饿
12         System.out.println("主任,我饿了");
13     }
14 }

代码说明: 代码行.3中 public是类的修饰符,表明该类是公共类,可以被其他类访问。class是定义类的关键字,Dog是类名称。

      代码行.4-5中 name、age是类的成员变量,也叫属性。

      代码行.7-9中 bark()是类中的函数,也叫方法,即定义犬吠这个方法。

      代码行.11-13中 hungry()是类中的函数,也叫方法。

PS:一个类的变量可以包含以下类型变量。

  • 局部变量:在方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在这个方法中,方法结束后,变量就会自动销毁。
  • 成员变量:在类中、方法体之外定义的变量。这种变量在创建变量的时候实例化(分配内存)。成员变量可以被类中的方法和特定类的语句访问。
  • 类 变 量 :也是在类中、方法体之外定义的变量,但必须声明为static类型。static也是修饰符的一种。

 

实例3-2

 1 package duke.example.ch3;
 2 
 3 public class Dog{
 4     String name;                    //名字
 5     int age;                            //年龄
 6 
 7     Dog(String name,int age){    //构造方法,没有返回值
 8         this.name=name;
 9         this.age=age;
10         System.out.println(name+“感谢主人天天带我玩耍!”);
11     }
12 
13      void bark(){                    //汪汪叫
14         System.out println("汪汪,不要过来");
15     }
16 
17     void hungry(){                //饥饿
18         System.out.println("主任,我饿了");
19     }
20 
21     public static void main(String[] args){
22         //创建对象时传递的参数要与构造方法参数列表对应
23         Dog myDog=new Dog("卡拉",3);
24         System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");
25     }
26 }

输出结果:

        卡拉感谢主人天天带我玩耍!
        我是一只小狗,我的名字叫卡拉,我3岁了!

代码说明: 代码行.7-9中 定义包含两个参数name和age的构造函数,构造方法的名称必须与类的名称Dog相同。构造方法不能有返回值,因为没有变量来接收返回值。

      代码行.23中 构造方法不能被显示调用,在类Dog实例化的过程中自动执行了。

代码执行顺序:

  1)先运行到代码行.21。这是程序的入口。

  2)然后运行代码行.23。这里要创建一个Dog,就要调用Dog的构造方法。

  3)运行到代码行.7。注意接下来并不是运行代码行.8,初始化一个类,必须先初始化他的属性。

  4)因此运行到代码行.4。然后是代码行.5。

  5)属性初始化后,才回到构造方法,执行里面的代码,也就是代码行.8-10。

  6)然后是代码行.11。表示创建一个Dog实例完成。

  7)然后回到main()方法中执行代码行.23-24。

  8)最后是代码行.25。main()方法执行完毕。

书上说作为程序员,应该知道程序的基本运行过程,否则不利于编写代码与进步,其实这是有道理的。在一个程序中,你看到的深度决定了你编程水平的上限。

 

实例3-3

 1 package duke.example.ch3;
 2 
 3 public class Dog{
 4     String name;                    //名字
 5     int age;                            //年龄
 6 
 7     Dog(String name,int age){    //构造方法,没有返回值
 8         this.name=name;
 9         this.age=age;
10         System.out.println(name+“感谢主人天天带我玩耍!”);
11     }
12 
13      void bark(){                    //汪汪叫
14         System.out println("汪汪,不要过来");
15     }
16 
17     void hungry(){                //饥饿
18         System.out.println("主任,我饿了");
19     }
20 
21     public static void main(String[] args){
22         //创建对象时传递的参数要与构造方法参数列表对应
23         Dog myDog=new Dog("卡拉",3);
24         //访问成员变量
25         String name=myDog.name;
26         int age=myDog.age;
27         System.out.println("我是一只小狗,我的名字叫"+name+",我"+age+"岁了!");
28         //访问方法
29         myDog.bark();
30         myDog.hungry();
31     }
32 }

输出结果:

        卡拉感谢主人天天带我玩耍!
        我是一只小狗,我的名字叫卡拉,我3岁了!
        汪汪,不要过来!
        主人,我饿了!

代码说明: 代码行.26-27中 通过点号(.)访问变量name和age。

      代码行.29-30中 通过点号(.)访问成员方法bark()和hungry()。

 

实例3-4

 1 package duke.example.ch3;
 2 
 3 public class Scope{
 4     public static String name="爪哇岛旅游攻略";        //类级变量
 5     public int i;                                                        //对象实例级变量
 6 
 7     //属性块,在类初始化属性时候运行
 8     {
 9         int j=2;                                                            //块级变量
10     }
11 
12     public void test(){
13         int j=3;                                                            //方法级变量
14         if(j==3){
15             int k=5;
16         }
17         //这里不能访问块级变量,块级变量只能在块内部访问
18         System.out.println("name="+name+",i="+i+",j="+j);
19     }
20 
21     public static void main(String[] args){
22         //不创建对象,直接通过类名访问类级变量
23         System.out.println(Scope.name);
24         //创建对象并访问它的方法
25         Scope.scope=new Scope();
26         scope.test();
27     }
28 }

输出结果:

        爪哇岛旅游攻略
        name=爪哇岛旅游攻略,i=0,j=3

代码说明: 代码行.4中 使用static关键字定义类级字符串变量name。

      代码行.12-19中 定义方法test(),方法内部定义了方法级变量和块级变量。

PS:  1)方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。

     2)块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。

     3)方法级和块级的变量必须被显式初始化,否则不能访问。

 

 实例3-5

 1 package duke.example.ch3
 2 
 3 public class ThisDemo1 {
 4     public int x=10;
 5     public int y=15;
 6 
 7     public void sum() {
 8         int z=this.x+this.y;
 9         System.out.println("x+y="+z);
10     }
11  
12     public static void main(String[] args) {
13         ThisDemo1 thisdemol=new ThisDemo1();
14         thisdemo1.sum();
15     }
16 }

输出结果:

        x+y=25

代码说明: 代码行.4-5中 定义成员变量x和y。

      代码行.8中 通过this点取成员变量。

PS:上面程序中,thisdemol时ThisDemol类的一个实例,this和thisdemol等价,执行int z=this.x+this.y;,就相当于执行int z=thisdemol.x+thisdemol.y;。

PS:this只有在类实例化后才有意义。

 

实例3-6

 1 package duke.example.ch3;
 2 
 3 public class ThisDemo2 {
 4     public String name;
 5     public int age;
 6 
 7     public ThisDemo2(String name,int age) {
 8         this.name=name;
 9         this.age=age;
10     }
11 
12     public void say() {
13         System.out.println("网站的名字是"+name+",已经成立了"+age+"年");
14     }
15 
16     public static void main(String[] args) {
17         ThisDemo2 thisdemo2=new ThisDemo2("www.baidu.com",15);
18         thisdemo2.say();
19     }
20 }

输出结果:

        网站的名字是www.baidu.com,已经成立了15年

代码说明: 代码行.7-10中 成员变量与方法内部的变量重名时,通过this引用调用成员变量。  形参的作用域是整个方法体,是局部变量。在ThisDemo2(String name,int age)中,形参与成员变量重名,如果不使用this,访问到的就是局部变量name和age,而不是成员变量。

      代码行.12-14中 在say()中没有使用this,因为成员变量的作用域是整个实例,当然也可以加上this。

        eg:System.out.println("网站的名字是"+this.name+",已经成立了"+this.age+"年"):

PS:Java默认将所有成员变量和成员方法与this关联在一起,因此使用this在某些情况下是多余的。

 

实例3-7

 1 package duke.example.ch3;
 2 
 3 public class ThisDemo3 {
 4     public String name;
 5     public int age;
 6 
 7     public ThisDemo3() {
 8         this("www.baidu.com",15);
 9     }
10 
11     public ThisDemo3(String name,int age) {
12         this.name=name;
13         this.age=age;
14     }
15 
16     public void say() {
17         System.out.println("网站的名字是"+name+",已经成立了"+age+"年");
18     }
19 
20     public static void main(String[] args) {
21         ThisDemo3 thisdemo3=new ThisDemo3();
22         thisdemo3.say();
23     }
24 }

输出结果:

        网站的名字是www.baidu.com,已经成立了5年

代码说明: 代码行.7-9中 在构造方法中,this调用另一个构造方法,调用动作必须置于最起始的位置。注意,不能在构造方法以外的任何方法内调用构造方法,在一个构造方法内只能调用一个构造方法。

PS:上述代码设计方法重载,即Java允许出现多个同名方法,只要参数不同即可。

 

实例3-8

 1 package duke.example.ch3;
 2 
 3 public class ThisDemo4 {
 4 
 5     public static void main(String[] args) {
 6         B b=new B(new A());
 7     }
 8 }
 9 
10 class A {
11     public A() {
12         new B(this).print();
13     }
14 
15     public void print() {
16         System.out.println("Hello from A!");
17     }
18 }
19 
20 class B {
21     A a;
22 
23     public B(A a) {
24         this.a=a;
25     }
26 
27     public void print() {
28         a.print();
29         System.out.println("Hello from B!");
30     }
31 }

输出结果:

        Hello from A!
        Hello from B!

代码说明: 代码行.12中 匿名对象就是没有名字的对象。如果对象只是用一次,就可以作为匿名对象,代码中new B(this).print();等价于(new B(this)).print();,先通过new B (this)创建一个没有名字的对象,再调用它的方法。

 

实例3-9

 1 package duke.example.ch3;
 2 
 3 public class Overload {
 4     //一个普通的方法,不带参数的
 5     void test() {
 6         System.out.println("No parameters");
 7     }
 8 
 9     //重载上面的方法,并且带了一个整型参数
10     void test(int a) {
11         System.out.println("a:"+a);
12     }
13 
14     //重载上面的方法,并且带了两个整型参数
15     void test(int a,int b) {
16         System.out.println("a and b:"+a+" "+b);
17     }
18 
19     //重载上面的方法,并且带了一个双精度参数
20     double test(double a) {
21         System.out.println("double a:"+a);
22         return a*a;
23     }
24 
25     public static void main(String[] args) {
26         Overload overload=new Overload();
27         overload.test;
28         overload.test(2);
29         overload.test(2,3);
30         overload.test(2,0);
31     }
32 }

输出结果:

        No parameters
        a:2
        a and b:2 3
        double a:2.0

PS:重载就是在一个类中,有相同的函数名称,但形参不同的函数。重载的结果,可以让一个程序段减少代码和方法的种类。

 

实例3-10

 1 package duke.example.ch3;
 2 
 3 public class Person {
 4     //封装属性:将属性设置为私有
 5     private String name;
 6     private int age;
 7 
 8     public  String getName() {                //外部通过此方法访问name属性
 9         return name;
10     }
11 
12     public void setName(String name) {    //该方法是外部赋值私有属性name
13         this.name=name;
14     }
15 
16     public int getAge() {                            //外部通过此方法访问age属性
17         return age;
18     }
19 
20     public void setAge(int age) {                //该方法使外部赋值私有属性age
21         shis.age=age;
22     }
23 
24     void say() {                                            //此方法可以被外部直接调用使用
25         System.out.println("我叫"+name+",今年"+age+"岁了!");
26     }
27 
28     public static void main(String[] args) {
29         Person person=new Person();    //实例化person类
30         person.setName("小芳");                    //通过开放方法给实例化对象的name属性赋值
31         person.setAge(22);                            //通过开放方法给实例化对象的age属性赋值
32         person.say();                                    //通过实例化对象的方法
33     }
34 }

输出结果:

        我叫小芳,今年22岁了!

代码说明: 代码行.5-6中 private是修饰符表示私有化,这就封装了类的属性,封装后外部不能直接使用该属性。

      代码行.7-22中 对外用标准的set/get方法修改/读取属性name和age的值。

      代码行.24中 定义方法say(),该方法可以被外部直接调用使用。

PS:封装的优点:

    1)隐藏类的实现细节。

    2)让使用者只能通过实现制定好的方法访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作。

    3)便于修改,增强了代码的可维护性。

 

总结:这一部分主要谈到了Java的类及其相关基础应用。另外,类的继承和多态是其高阶应用。

posted @ 2017-04-08 02:58  血夜之末  阅读(764)  评论(0编辑  收藏  举报