面向对象简介
面向对象是一种程序的设计,但是并不表示世界上所有的开发者都认同面向对象。因为有很多的开发者认为面向对象过于复杂,所以更多的人愿意使用函数式编程。
面向对象的前身属于面向过程,如果要先笼统的去解释这两种开发模型的区别,最好的例子:面向过程是解决问题,而面向对象是模块化设计。对于现在的程序开发更多情况下就像是汽车组装一样,不同的工厂生产不同的配件。将所有的零件组装在一起,就可以形成一辆汽车,并且当某一个零件坏掉的时候还可以进行配装。
在面向对象里面实际还有许多特点,归结起来有如下三类:
- 封装性:内部操作对外部而不可见;
- 继承性:在上一辈基础上继续发展;
- 多态性:这是一个最为重要的环节,利用多态性才可以得到良好的设计。
那么进行面向对象开发的时候也有三个阶段:OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象编程)。
所有的程序的开发原则都离不开实际生活。如果从程序的开发角度来讲,面向对象给我们最大的特征:可以进行生活的抽象。
类与对象
类与对象是整个面向对象的核心所在,也是所有概念基础。类本身属于引用数据类型,所以类的使用上会牵扯到内存的分配问题。
##类与对象基本定义
现在大家可以看懂我的文字,我们具备共同的特征:我们都是中国人,母语都是汉语,而且身体正常。那么具备这些共同特征的人有很多,那么自然就是是一个群体,而群体的特征就是整个类的定义概念。所谓类描述的就是共性特征。
任何时候只是依靠共性的特征是无法进行精准描述的,那么就需要一些个性化的特点。就可以描述一个个独立的事物。所以这样就可以推断出:所谓类指的是就是一个共性的概念,而对象指的是一个具体的可以使用的的事物。
那么很明显在实际的开发之中,一定需要首先产生类,而后才可以产生对象。那么对象的所有操作行为都一定在类中进行了完整的定义。类中没有定义的功能,那么对象一定无法使用。
类中的组成:方法(操作的行为)、属性(变量,描述每一个对象的具体特点)。
##类与对象定义及使用
如果在程序之中要进行类的定义可以使用class关键字完成,而定义的语法如下:
class 类名称 { //所有的程序都要以“{}”作为分界符
属性;
属性;
方法(){};
}
此时的方法不再由主类直接调用,而是要通过对象进行调用。
范例: 定义类
class Person { //定义一个类,类名称每个首字母要求大写
String name; // 表示人的姓名
int age; // 表示人的年龄
public void info() {
System.out.println("name = " + name + "、age = " + age);
}
}
在这个类中只是定义了两个属性和一个方法,特别需要注意的是,类中可以定义的属性个数以及方法数量是没有限制的,而且在编写的时候,每一个方法中的代码尽量不要特别长。
类定义后是不能直接去使用的,如果要想使用类那么必须产生对象,而对象的定义分为以下两种语法形式:
- 声明并实例化对象:类名称 对象名称 = new 类名称();
- 分布进行对象实例化:
- 声明对象:类名称 对象名称 = null;
- 实例化对象:对象名称 = new 类名称();
引用数据类型的最大特征在于内存的分配操作,而只要出现有关键字new那么就只有一个解释:开辟新内存(内存是不可能无限开辟的,所以这个时候所谓的性能调优的就是内存问题)。
所有的对象只有实例化之后才可以真正使用,而对象的使用都是围绕着类进行的,那么此时就有两种形式。
- 调用类中的属性:对象.属性 = 内容;
- 调用类中的方法:对象.方法();
范例: 声明并实例化对象
public class TestDemo {
public static void main(String[] args) {
//类名称 对象名称 = new 类名称();
Person per = new Person(); //这个时候就表示实例化了一个per对象
per.name = "张三"; // 设置对象中的属性
per.age = 18; // 设置对象中的属性
per.info(); // 调用类中的方法
}
}
以上就实现了一个最基本的类的定义以及对象的使用。
对象的产生分析
如果要想进行对象的产生分析,那么首先就必须清楚引用类型。引用类型指的是内存空间的操作。而对于现在的内存主要会使用两块内存空间:
- 堆内存空间:保存真正的数据,堆内存保存的是对象的属性信息;
- 栈内存空间:保存的堆内存的地址,堆内存操作权,如果要简化理解,可以理解为保存的是对象名称;
所以按照之前的程序,那么现在就可以给出如下的内存参考图:
但是对于对象的产生实际要知道一共会有两种格式,现在使用的是声明实例化对象的格式,那么也可以分步的方式完成。
public class TestDemo {
public static void main(String[] args) {
//类名称 对象名称 = new 类名称();
Person per = null; // 声明一个新的对象
per = new Person(); // 实例化对象
per.name = "张三"; // 设置对象中的属性
per.age = 18; // 设置对象中的属性
per.info(); // 调用类中的方法
}
}
但是千万要记住一点,对象(所有的引用数据类型)必须在其开辟空间之后才可以使用。如果使用了未开辟内存空间的引用数据类型,则将出现NullPointerException。
class Person { //定义一个类,类名称每个首字母要求大写
String name; // 表示人的姓名
int age; // 表示人的年龄
public void info() {
System.out.println("name = " + name + "、age = " + age);
}
}
public class TestDemo {
public static void main(String[] args) {
//类名称 对象名称 = new 类名称();
Person per = null; // 声明一个新的对象
per.info(); // 调用类中的方法
}
}
这个时候只声明了对象,而并没有为其开辟堆内存空间,而本程序在编译的时候不会产生任何的语法错误,但是执行的时候会出现如下的错误提示:
Exception in thread" main" java.lang.NullPointerException
at TestDemo.main(TestDemo.java:14)
“NullPointerException” 是在我们整个的开发人生之中会一直陪伴到你最后的一个异常。只有引用数据类型(数组、类、接口)才会产生此类异常,以后出现了就根据错误的位置观察该对象是否实例化。
引用传递初次分析
所有初学者最难的部分就是引用传递分析。以后的开发之中都是引用传递。
引用传递的本质就在于别名,而这个别名只不过是放在了栈内存之中,即:一块堆内存可以被多个栈内存所指向。
范例: 观察引用传递
class Person {
String name;
int age;
public void info() {
System.out.println("name = " + name + "、age = " + age);
}
}
public class TestDemo {
public static void main(String[] args) {
Person per1 = new Person();
per1.name = "小于";
per1.age = 10;
//此步骤就是引用传递的操作
Person per2 = per1; //采用同样的类型接受
per2.name = "狗剩";
per1.info();
}
}
此时需要通过内存关系图来进行程序的执行观察。
范例: 观察引用传递
class Person {
String name;
int age;
public void info() {
System.out.println("name = " + name + "、age = " + age);
}
}
public class TestDemo {
public static void main(String[] args) {
Person per1 = new Person();
Person per2 = new Person();
per1.name = "小于";
per1.age = 10;
per2.name = "李四";
per2.age = 22;
//此步骤就是引用传递的操作
per2 = per1; //采用同样的类型接受
per2.name = "狗剩";
per1.info();
}
}
观察此时的内存分析图:
在程序开发过程之中,所谓的垃圾空间指的就是没有任何栈内存指向的对内存空间,所有的垃圾空间将不定期被Java垃圾收集器(GC、Garbage Collector
)进行回收以实现内存空间的释放,不过从实际开发来讲,虽然Java提供有GC
,但是GC
也会造成程序性能下降,所以开发过程之中一定要控制对象的产生数量,即:无用的对象尽可能少产生。