一、面向对象简述。
面向对象是一种现在最为流行的程序设计方法,谈到面向对象就不得不提及面向过程。
这是两种不同的程序设计方法,常见的c语言用的是面向过程,而java、c++用的是面向对象。
对两种思想抽象地定义,
面向过程是围绕功能进行的,为每一个功能写一个函数,需要考虑其中的每一个细节,以步骤划分;
而面向对象则像是组装,先确定一个系统是由哪些对象组成,再分别去设计这些对象,将它们像零件一样组装起来形成有完整功能的系统。
再具体举一个常用的例子:用这两种方法分别实现“把大象放进冰箱”。
面向过程:肢解大象-打开冰箱-放入大象-关闭冰箱
面向对象:大象(肢解功能、移动功能)、冰箱(打开功能、装载功能、关闭功能)。
面向对象的三大特性。
(1)封装:保护内部的操作不被破坏;
(2)继承:在原本的基础之上继续进行扩充;
(3)多态:在一个指定的范围之内进行概念的转换。
二、类与对象的基本概念
类与对象时整个面向对象中最基础的组成单元。
类:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
比如说:人类是一个类,每一个人是类中的一个对象,每个人都有身高,体重,性别,外貌等等的属性。
在编程设计中,我们需要定义一个类,再给对应的类定义具体对象。
三、类与对象的定义和使用
类定义范式:
class 类名称{
属性;
行为;
}
定义Person类:
class Person{
String name;//名字
int height;//身高
int age;//年龄
public void walk(){
System.out.print(name+"会走路");
} //走路
public void tell(){
System.out.print("名字:"+name+";"年龄:"+age);
}
}
类定义完成之后,无法直接使用。如果要使用,必须依靠对象,对象的产生格式(两种格式)如下:
(1)格式一:声明并实例化对象
类名称 对象名称 = new 类名(); //格式
Person person = new Person();//Person实例
(2)格式二:先声明对象,再实例化对象
类名称 对象名称 = null;
对象名称 = new 类名(); //格式
Person person = null;
person = new Person(); //Person实例
不同于int、String、char等基本数据类型,类属于引用数据类型,而引用数据类型在使用时需要用内存空间的分配和使用,关键字new就是用来分配内存的。
实例化一个对象后,可以用关键字"."对对象进行类的操作,比如定义属性具体值,使用方法。
对象名.属性名 = 具体值;
对象名.方法名();
person.age = 18;
person.walk();
接下来用在eclipse实践一下这两种实例化对象的方法。
格式一:
package com.alex.classtest;
class Person {
String name ;
int age ;
public void get() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class TestDemo {
public static void main(String args[]) {
Person per = new Person() ;// 声明并实例化对象
per.name = "张三" ;//操作属性内容
per.age = 30 ;//操作属性内容
per.get() ;//调用类中的get()方法
}
}
运行结果:
姓名:张三,年龄:30
格式二:
package com.alex.classtest;
class Person {
String name ;
int age ;
public void get() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class TestDemo {
public static void main(String args[]) {
Person per = null;//声明对象
per = new Person() ;//实例化对象
per.name = "张三" ;//操作属性内容
per.age = 30 ;//操作属性内容
per.get() ;//调用类中的get()方法
}
}
运行结果:
姓名:张三,年龄:30
我们可以发现,得到的结果是一样的。那么这两种方式的区别在哪呢?
说到这里就必须从内存的角度来分析。
首先,给出两种内存空间的概念:
(1)堆内存:保存对象的属性内容。堆内存需要用new关键字来分配空间;
(2)栈内存:保存的是堆内存的地址(在这里为了分析方便,可以简单理解为栈内存保存的是对象的名字)。
任何情况下,只要看见关键字new,都表示要分配新的堆内存空间,一旦堆内存空间分配了,里面就会有类中定义的属性,并且属性内容都是其对应数据类型的默认值。
上面两种对象实例化对象方式内存表示如下:
两种方式的区别在于①②,第一种声明并实例化的方式实际就是①②组合在一起,而第二种先声明然后实例化是把①和②分步骤来。
如果使用了没有实例化的对象,则会程序运行结果会报错。
package com.alex.classtest;
class Person {
String name ;
int age ;
public void get() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
public class TestDemo {
public static void main(String args[]) {
Person per = null;//声明对象
//per = new Person() ;//实例化对象
per.name = "张三" ;//操作属性内容
per.age = 30 ;//操作属性内容
per.get() ;//调用类中的get()方法
}
}
运行结果:
Exception in thread "main" java.lang.NullPointerException
at com.wz.classandobj.TestDemo.main(TestDemo.java:15)
错误信息表示的是“NullPointerException(空指向异常)”。是因为程序只声明了Person对象,但并没有实例化Person对象(只有了栈内存,并没有对应的堆内存空间),程序在编译的时候不会出现任何的错误,但是在执行的时候出现了上面的错误信息。
四、对象引用传递初步分析
引用传递定义上指的是同一块堆内存空间,可以同时被多个栈内存所指向,不同的栈可以修改同一块堆内存的内容。
也就是说同一个对象的属性内存被两个不同命名的对象共同使用。
看下面实例
class Person {
String name ;
int age ;
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age) ;
}
}
public class TestDemo {
public static void main(String args[]) {
Person per1 = new Person() ; // 声明并实例化对象
Person per2 = new Person() ;
per1.name = "张三" ;
per1.age = 20 ;
per2.name = "李四" ;
per2.age = 30 ;
per2 = per1 ;// 引用传递
per2.name = "王五" ;
per1.tell() ;
}
}
输出的结果是:
姓名:王五,年龄:20
在这个过程中,内存空间是这样变化的:
垃圾:指的是在程序开发之中没有任何对象所指向的一块堆内存空间,这块空间就成为垃圾,所有的垃圾将等待GC(垃圾收集器)不定期的进行回收与空间的释放。
五、面向对象的封装性
在定义类时,在class或者属性变量之前加上修饰词public、private、default、protected表示它的被访问权限。
先看属性变量没有修饰词也就是默认(default)的时候,
class Book{
String title;
double price;
public void getInfo(){
System.out.println("图书的名称:"+title+" 图书的价格:"+price);
}
}
public class TestDemo {
public static void main(String args[]) {
Book book = new Book();
book.title = "Quanta";
book.price = 99;
book.getInfo();
}
}
输出的结果是:
图书的名称:Quanta 图书的价格:99
当属性变量修饰词为private时:
class Book{
private String title;
private double price;
public void getInfo(){
System.out.println("图书的名称:"+title+" 图书的价格:"+price);
}
}
public class TestDemo {
public static void main(String args[]) {
Book book = new Book();
book.title = "Quanta";
book.price = 99;
book.getInfo();
}
}
运行结果:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The field Book.title is not visible
The field Book.price is not visible
at com.wz.classandobj.TestDemo.main(TestDemo.java:16)
也就是在加入private修饰词后无法再Book类的外部直接调用它的属性了。
那么如何在类外部访问Book类内的private(私有)变量呢?这时候可以用到setter、getter方法。
为Book类定义属性相应的setter和getter方法,以Book类为例:
class Book{
private String title;
private double price;
public void setTitle(String title){
this.title = title;
}
public String getTitle(){
return title;
}
public void setPrice(double price){
this.price = price;
}
public double getPrice(){
return price;
}
public void getInfo(){
System.out.println("图书的名称:"+title+" 图书的价格:"+price);
}
}
class TestDemo {
public static void main(String args[]) {
Book book = new Book();
book.title = "Quanta";
book.price = 99;
book.getInfo();
}
}