首页 > 代码库 > 第三 章、面向对象 第一步部分

第三 章、面向对象 第一步部分

一、类与对象的基本概念

类:抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);

对象:是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性区分不同的对象。

类与对象的区别:类是对象的模板,对象是类的实例,类只有通过对象才可以使用,开发中应该先产生类,再产生对象。类不能直接使用,方法可以直接使用。

二、类与对象的定义

1、类的定义:

在JAVA中定义类,可以使用class关键字完成, 语法为:

1 class 类名称{2     属性(变量);3     行为(方法);4 }

范例:定义一个Person类。

1 class Person {2     String name;3     int age;4 5     public void tell() {6         System.out.println("姓名:" + name + ",年龄:" + age);7     }8 }

2、对象的定义:

定义完类之后,无法直接使用,要使用,必须依靠对象使用,由于类属于引用数据,对象的定义格式如下:

格式一:声明并实例化对象

类名称   对象名称   =  new  类名称  ()

格式二:分布完成

声明对象:     类名称   对象名称 = null;

实例化对象:  对象名称 =  new  类名称();   

以后只要是引用数据类型的实例化操作,永远都会存在关键字new(分配空间)。当一个实例化的对象产生后,可以按照如下方式进行类的操作:

  • 方法.属性:表示调用类之中的属性
  • 方法.对象():表示调用类之中的方法

范例1:使用对象操作类

 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 } 9 10 public class TestPerson {11     public static void main(String[] args) {12         Person1 per = new Person1();13         per.name = "张三";14         per.age = -30;15         per.tell();16     }17 }

姓名:张三,年龄:-30

格式二分步完成操作类,范例2

技术分享
 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 } 9 10 public class TestPerson {11     public static void main(String[] args) {12         Person1 per = null;13         per = new Person1();14         per.name = "张三";15         per.age = -30;16         per.tell();17     }18 }
View Code

姓名:张三,年龄:-30

格式一与格式二运行结果一致,两者的区别引入内存解释:

堆内存:保存真正的数据

栈内存:保存一块堆内存的空间地址

技术分享

上图为上述程序的内存分析图,过程:声明对象——实例化对象——为对象的name属性赋值——为对象的age属性赋值

范例3、产生两个对象的操作:

 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 } 9 10 public class TestPerson {11     public static void main(String[] args) {12         Person1 per2 = new Person1();13         Person1 per1 = null;14         per1 = new Person1();15 16         per1.name = "张三";17         per2.name = "李四";18         per1.age = 30;19         per2.age = 20;20         per1.tell();21         per2.tell();22     }23 }

 

姓名:张三,年龄:30
姓名:李四,年龄:20

技术分享

内存分析图:声明per1,声明并实例化per2——实例化per2——为per1对象属性赋值——为per2对象属性赋值

 范例4、异常代码:

 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 } 9 10 public class TestPerson {11     public static void main(String[] args) {12         Person1 per1 = null;//只声明,未实例化per1,只有栈内存,没有堆内存13         per1.name = "张三";14         per1.age = 30;15         per1.tell();16 17     }18 }

运行结果:Exception in thread "main" java.lang.NullPointerException(空间指向异常)
              at hello.TestPerson.main(TestPerson.java:15)
这种异常只会在在用数据类型产生,并很常见,解决方案:查找引用数据类型,观察其是否被实例化

引用传递:同一块堆内存空间同时被多个栈内存所指向,不同的栈可以修改同一块堆内存的内容。

范例4:

 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6  




System.out.println("姓名:" + name + ",年龄:" + age); 7 } 8 } 9 10 public class TestPerson {11 public static void main(String[] args) {12 Person1 per1 = new Person1();13 per1.name = "张三";14 per1.age = 20;15 Person1 per2 = per1;16 per2.name = "李四";17 per1.tell();18 19 }20 }

姓名:李四,年龄:20

技术分享

范例5:

 1 class Person1 { 2     String name; 3     int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 } 9 10 public class TestPerson {11     public static void main(String[] args) {12         Person1 per1 = new Person1();13         Person1 per2 = new Person1();14         per1.name = "张三";15         per1.age = 20;16         per2.name = "李四";17         per2.age = 30;18         per2 = per1;19         per2.name = "王五";20         per1.tell();21 22     }23 }

结果:姓名:王五,年龄:20

技术分享

垃圾:在开发程序中,没有任何对象所指向的一块堆内存空间,这块内存空间被称为垃圾,所有垃圾等待GC(垃圾收集器)不定期的进行回收与空间的释放。

 3、封装性

范例1:

1 public class Person1 {2     String name;3     int age;4 5     public void tell() {6         System.out.println("姓名:" + name + ",年龄:" + age);7     }8 }
1 public class TestDemo2{2     public static void main(String[] args) {3         Person1 p = new Person1();4         p.name="王娜";5         p.age=-30;6         p.tell();7     }8 }

运行结果:姓名:王娜,年龄:-30

虽然年龄不可能为负数,但是依然可以执行,这属于业务逻辑错误,出错的关键是没有检查要设置的内容,检查的第一步是让用户看不见操作的东西,此时,用private关键字,将类中的属性进行私有化操作。

范例2:使用private封装类中属性

 1 class Person4 { 2     private String name; 3     private int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8  9 }10 11 public class Person3 {12     public static void main(String[] args) {13         Person4 per = new Person4();14         per.name = "张三";//语法错误,无法访问私有属性15         per.age = -30;//语法错误,无法访问私有属性16         per.tell();//对象.方法17     }18 }

Exception in thread "main" java.lang.Error: Unresolved compilation problems:
    The field Person4.name is not visible
    The field Person4.age is not visible
    at hello.Person3.main(Person3.java:16)    属性被封装,但是无法被外部操作,为此,如果访问类中的私有属性,按如下形式定义操作方法:
setter(以"private String name"属性为例):public void setName(String n);

getter(以"private String name"属性为例):public void getName().

范例3:编写setter()和getter()方法

 

 1 public class Person { 2     private String name; 3     private int age; 4  5     public void setName(String n) { 6         name = n; 7     } 8  9     public void setAge(int a) {10         age = a;11     }12 13     public String getName() {14         return name;15     }16 17     public int getAge() {18         return age;19     }20 21     public void tell() {22         System.out.println("姓名:" + name + ",年龄:" + age);23     }24 }
1 public class Person1 {2     public static void main(String[] args) {3         Person per=new Person();4         per.setName("张三");5         per.setAge(20);6         per.tell();7     }8 }

姓名:张三,年龄:20

虽然以上代码可以访问,但是没有加入验证。在开发时,加入验证是在setter中加入,getter只是简单的将数据返回。

范例4:加入验证

 1 public class Person { 2     private String name; 3     private int age; 4  5     public void tell() { 6         System.out.println("姓名:" + name + ",年龄:" + age); 7     } 8 public void setName(String n){ 9     name=n;10 }11 public void setAge(int a){12     if(a>=0&&a<=0){13     age=a;14 }15 }16 public String setName(){17     return name;18 }19 public int setAge(){20     return age;21 }22     }
1 public class Person1 {2     public static void main(String[] args) {3         Person per=new Person();4         per.setName("张三");5         per.setAge(-20);6         per.tell();7     }8 }

姓名:张三,年龄:0

年龄是-20,不符合逻辑,故置0.

以后在定义类的时候,所有属性都要编写private封装,封装后的属性如果需要被外部操作,则编写setter()和getter()。

4、构造方法(构造方法是在实例化对象的时候使用,而普通方法是在实例化对象产生之后使用的)

定义:构造方法的名称和类名称保持一致;

         构造方法不允许有返回值声明;

         由于对象实例化操作一定需要构造方法的存在,所以,如果在类中没有明确定义构造方法的话,则会自动生成一个无参,无返回值的构造方法,如果一个类之中已经明确定义了一个构造方法的话,则无实际意义的构造方法就不会自动生成,即一个类之中至少存在一个构造方法。

范例4.1:默认情况下会存在一个无参无返回值的构造方法。

1 class Person(){//类名称首字母大写2     public Person(){//无参无返回值的方法3     }4 }

作用:在对象实例化的时候,通过构造方法为类中的属性初始化。

范例4.2:在类中定义有参构造方法。

 1 public class Person {                                      //类名称首字母大写 2     private String name;                                   //属性封装 3     private int age;                                       //属性封装 4  5     public Person(String n, int a) {                       //通过构造方法赋值 6         setName(n);                                        //设置name属性内容 7         setAge(a);                                         //设置age属性内容 8     } 9 10     public void tell() {11         System.out.println("姓名:" + name + ",年龄:" + age);12     }13 14     public void setName(String n) {                         //setter:设置name属性内容15         name = n;16     }17 18     public void setAge(int a) {                              //setter:设置age属性内容19         if (a >= 0 && a <= 250) {                            //增加检查20             age = a;                                         //满足条件赋值21         }22     }23 24     public String getName() {                                //getter:取得name属性25         return name;26     }27 28     public int getAge() {                                     //getter:取得age属性29         return age;30     }31 }
1 public class TestDem {2     public static void main(String[] args) {3         Person per = new Person("张三", 30);// 声明并实例化对象4         per.tell();// 对象.方法()5     }6 }

姓名:张三,年龄:30

 另外:可以用”this.()方法“表示调用本类中的方法,以下代码与范例4.2中代码一样

1 public Person(String n, int a) {                       //通过构造方法赋值2         this.setName(n);                         //设置name属性内容3         this.setAge(a);                           //设置age属性内容4     }

范例4.3:构造方法重载

 1 public class Person { // 类名称首字母大写 2     private String name; // 属性封装 3     private int age; // 属性封装 4  5     public Person() { // 无参构造方法 6     } 7  8     public Person(String name) { 9         this.setName(name);10     }11 12     public Person(String n, int a) {13         setName(n);14         setAge(a);15     }16 17     public void tell() {18         System.out.println("姓名:" + name + ",年龄" + age);19     }20 21     public void setName(String n) {22         name = n;23     }24 25     public void setAge(int a) {26         if (a >= 0 && a <= 250) {27             age = a;28         }29     }30 31     public String getName() {32         return name;33     }34 35     public int getAge() {36         return age;37     }38 }
public class TestDem {    public static void main(String[] args) {        Person per = new Person("张三");// 声明并实例化对象        per.tell();// 对象.方法()    }}

姓名:张三,年龄0

在本程序Person类中定义了三个构造方法,在主类中实例化对象时调用了一个参数的构造,结果只为name赋值,年龄为0.

在一个类中对构造方法重载时,所有的重载方法按照参数的个数由多到少或由少到多

5、匿名对象

按内存关系,对象名称可以被解释为在栈内存中保存,而对象的具体内容(属性)在对内存之中保存,所以匿名对象没有对应的栈内存指向,只能使用一次,一次之后将成为垃圾,并且等待GC回收释放。

范例:

 1 public class Person { 2     private String name; 3     private int age; 4  5     public Person(String n, int a) { 6         name = n; 7         age = a; 8     } 9 10     public void tell() {11         System.out.println("姓名:" + name + ",年龄" + age);12     }13     // settter、getter省略14 }
1 public class TestDem {2     public static void main(String[] args) {3         new Person("张三", 20).tell();// 匿名对象.方法4     }5 }

姓名:张三,年龄20

 

第三 章、面向对象 第一步部分