前言
同時學習java和python或其他語言的小朋友,肯定發現了一個問題,java實體類有冗長的setter和getter,但是Python就不用,那么造成這個現象的原因是什么呢?為什么java不像Python直接把屬性設置為public就完事了?
不能只隨波逐流別人寫就跟着寫要通過現象看本質。
一、面向對象的封裝理念
這應該是最多人給你的答案,封裝類的內部細節提供對應的方法,有時候可以對屬性賦值的設置進行限制,如下通過setter方法,指定了年齡輸入范圍只在0-120
class Person{
private int age;
public void setAge(int age){
if(age <= 0 || age > 120){
throw new RuntimeException("年齡范圍不合法");
}
this.age = age;
}
public int getAge(){
return this.age;
}
}
或者部分屬性讀寫權限分離 只提供讀(getter)或寫(setter)其中一種權限。如下情況外部對於Person類的age只有讀的權限沒有寫的權限,如果直接把age設置成public無法做到這么精確的控制。
class Person{
private int age;
public int getAge(){
return age;
}
}
但這個理由其實並不太站得住腳,
- 絕大多數我們java實體類的setter、getter方法都是使用idea默認生成的,並沒有對其做任何修改。所有起不到什么精確控制讀寫功能。
- 同為面向對象的Python、js就沒聽過有人寫setter和getter。當然你要是想在python寫setter也沒人會攔着你,但是主流環境下沒人這么做肯定是有他的原因。
- 阿里巴巴開發手冊明確規定不能修改默認生成的setter、getter。那么我們通過修改這兩個方法來精確控制屬性值讀寫就屬於不規范操作。
二、面向對象的多態
Java中方法是可以多態而屬性是不能多態的,直接上代碼
父類:
class Animal{
public String name = "動物";
public String getName(){
return name;
}
}
子類:
class Cat extends Animal{
public String name = "貓咪";
public String getName(){
return name;
}
}
//父類引用指向子類對象
Animal animal = new Cat();
System.out.println(animal.name);
System.out.println(animal.getName());
輸出結果為:
動物
貓咪
通過這個例子就不難知道為什么java需要setter、getter而Python就不需要了。
不僅僅是Python,幾乎所有動態語言都沒有setter和getter
其實有些人說這是動態類型語言優雅簡潔的優點,實際上是動態類型沒有什么“父類引用指向之類對象”的概念,他們就算想通過setter、getter來實現多態也做不到啊。索性就不要咯。
三、java的解決方案:Lombok
這么冗長的setter和getter其實並非無解,java有一個很實用的插件Lombok,使用方法如下
在pom.xml
引入依賴
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
/**
*加入這兩個注解自動生成setter、getter
*/
@Setter
@Getter
class Person{
private String name;
}
總結
java的setter、getter設計初衷一小部分原因是為了封裝內部細節,但這占比非常小。
真正導致實體類setter、getter不可或缺的根本原因 是java中屬性不能多態,只有方法可以多態。
動態類型語言因為沒有類型系統,沒有‘完整’的多態特性,所以並不需要。