文章目录
前言
面向对象的基础就在于类和对象,有了解过的人应该都知道“类是抽象化的对象,对象是实例化的类。”
类是抽象化的对象:比如说张三和李四都是人,则单纯从属性或者说特点上来说都是完全相同的。当所有的属性都抽象化以后(可以理解为不做特别指定)后本身不带有任何属性的一个对象就是一个类,即人类。
对象是实例化的类:比如人类都有:身高、姓名、体重、性别等等各种的属性,但是不做特别指定则无法确切的表明某一个具体的事物。换言之当所有的属性都进行了指定后,即可明确一个具体化的对象。
一、类
类是面向对象的基础,在面向对象编程中,几乎所有的数据都可以看成是一个对象。基本数据类型也有对应的类来进行装拆箱处理。
1.封装和隐藏
出于安全性考虑,面向对象编程中某一个对象的自身的属性为了防止外部的非法修改需要进行封装处理。
如原来声明某一个“人”类时,我们可能会像这样写:
/**
* @author Silence_Lurker
*/
public class Person{
String name;
String id;
boolean sex;
public Person(){
}
public Person(String name, String id, boolean sex){
this.name = name;
this.id = id;
this.sex = sex;
}
@Override
public String toString(){
return "name:" + name + "\r\nid:" + id + "sex" + (sex ? "男" : "女");
}
}
这样乍一看没问题,但是在外部实例化一个对象后,这些属性是对外可见的。如下例:
/**
* @author Silence_Lurker
*/
public class App {
public static void main(String[] args) {
// 假定true为男性,false为女性
Person personZhang = new Person("张三", "1***************35", true);
Person personLi = new Person("李四", "1***************45", false);
System.out.println(personZhang.toString());
System.out.println(personLi.toString());
}
}
数据的确是可以正常输出,但是我们可以发现数据是可以被外部直接进行访问并修改的,如下:
/**
* @author Silence_Lurker
*/
public class App {
public static void main(String[] args) {
// 假定true为男性,false为女性
Person personZhang = new Person("张三", "1***************35", true);
Person personLi = new Person("李四", "1***************45", false);
System.out.println(personZhang.toString());
System.out.println(personLi.toString());
personZhang.name = "张四";
personLi.sex = true;
System.out.println(personZhang.toString());
System.out.println(personLi.toString());
}
}
运行后可以发现数据被直接修改了。但这在实际开发过程中是很不合理的。这时候我们就需要通过访问修饰符进行封装处理。、
访问修饰符:
修饰符 | 访问权限 |
---|---|
private | 私有化的,对外部不可见(仅该类内部可见),需要通过setter和getter方法进行访问 |
{default}(即不写,不标识) | 默认标识符,也叫作友好(friendly)标识符对同包内可见,外部包不可见。 |
protected | 受保护的,对外部不可见但对子类可见。同样需要通过setter和getter方法来进行访问。但子类可直接进行访问 |
public | 公共标识符,对外部均可见 |
在合适的时候选用合适的标识符可以保证程序的安全性。
2.类的定义
一个类主要由属性和方法构成,最简单的类只要有类标识符和类名即可,如下:
class Test{ // 这也是一个类。
}
类前也可以加访问修饰符,但一个java文件内只能有一个public修饰的类,可以称其为“主类”。在类中也可以进行类的声明,叫做“内部类”(理论上可以无线套娃,但是没人会这样写的。)
最常见的类的定义如下:
public class HumanBeing{
private String id;
private String name;
// ... 以上为属性 ...
// ... 以下为方法 ...
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
}
属性和方法的声明本身并没有顺序要求,但是可以提高代码的可读性。但如果有部分属性仅有单个或极少量的方法会对其进行操作则可以直接声明于方法上方。
3.方法的重载
方法的重载最简单的理解就是方法名相同,参数类型不同。如下:
public class Test{
private int sum;
private int average;
public int add(int a, int b){
return a+b;
}
public int add(int a, int b, int c){
return a+b+c;
}
public int add(int...num){ // 这种参数声明方式表明不明确具体传入多少个参数,但所有参数传入后会被作为一个名为num的int型数组进行处理。
sum = 0;
for(int i = 0 ; i < num.length ; i++){
sum += num[i];
}
return sum;
}
}
可以发现三个方法名都是add但是在参数数量和类型上有所不同。这就是方法的重载。但是注意:以下这种方法是不成立的:
public class Test{
private int sum;
private int average;
public int add(int a, int b){
return a+b;
}
public int add(int b, int a){
return b+a;
}
}
因为参数是按照数据类型和数量进行匹配,所以当类型和顺序完全相同时是不能进行重载的。因为对java来说两个方法都是add(int,int)所以无法进行区分。
4.方法的递归
即方法递归调用,最常见的是用于斐波那契数列或单链表、树等数据结构的遍历。即方法内部调用该方法本身,在得到结果前一直进行同样的操作。这里不再赘述。
二、对象
所有的对象均为类的实例化,最常用的实例化方法就是通过构造方法,后期设计模式的学习中会学习到通过工厂设计模式来实现动态产生实例化对象,这里先不提。
1.构造方法
所有的类在编写的时候默认有一个无参构造方法,比如下面的这两段代码等价:
public class Person{
private String name;
// setter、getter方法略
}
public class Person{
private String name;
public Person(){}
// setter、getter方法略
}
但一旦声明了自定义的构造方法,无参构造方法会默认删除,如果有需求则需要手动进行添加。如下:
public class Person{
private String name;
public Person(String name){
this.name = name;
}
// 未进行无参构造的声明,若调用则报错提示无参构造未声明
}
public class Person{
private String name;
public Person(){
}
public Person(String name){
this.name = name;
}
}
注意,构造方法没有返回值,若添加返回值进行修饰则会认为是一个普通方法,这就和初衷相悖了。
单例设计模式
这是一种最简单的设计模式,即将构造方法进行隐藏,所有方法均为静态方法。如JDK自带的Math类就是典型的单例设计模式。
2.new关键字
new关键字主要用于实例化对象,本身的作用是根据构造方法分配一块新的内存空间,但可以粗略的理解为“新建”的意思。如下例:
/**
* @author Silence_Lurker
*/
public class App {
public static void main(String[] args) {
// 假定true为男性,false为女性
Person personZhang = new Person("张三", "1***************35", true);
Person personLi = new Person();
personLi.setId("1***************45");
personLi.setName("李四");
personLi.setSex(false);
System.out.println(personZhang.toString());
System.out.println(personLi.toString());
}
}
这就是最简单的样例,可以发现声明一个新的对象后,需要通过new 构造方法(参数)的形式进行赋值。同时也可以发现含参构造的作用,即可以忽略掉后期手动输入数据来进行信息录入的缺点。而且通过含参构造可以配合无setter方法使对象声明后无法进行数据修改。最大限度保证数据安全性。
构造方法也可以粗略理解为一个返回一个该类的实例化对象的方法。即:
public static Person Person(){
return new Person();
}
可行但是完全没必要。
this关键字
在上面的例子中出现了this关键字,this关键字主要用于当类的属性和传入参数的属性名称相同时进行区分。this可以指代当前类对象(也可以直接理解成当前类),如下例:
public class Person{
private String name;
public Person(String name){
this.name = name;
}
}
这里的this.name是类中的私有属性name,第二个name是构造方法中传入的参数name,在变量名相同的情况下,没有this则表示传入的参数的属性。即局部变量。