首页 > 代码库 > 第三 章、面向对象 第一步部分
第三 章、面向对象 第一步部分
一、类与对象的基本概念
类:抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象:是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性区分不同的对象。
类与对象的区别:类是对象的模板,对象是类的实例,类只有通过对象才可以使用,开发中应该先产生类,再产生对象。类不能直接使用,方法可以直接使用。
二、类与对象的定义
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 }
姓名:张三,年龄:-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
第三 章、面向对象 第一步部分