一、封装
封装是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。在java中我们一般使用private对类中属性或方法进行封装。
使用封装能够更好的保护代码,防止有的代码被其他类的代码随意访问,加强了代码的安全性;而且适当的封装能使代码更容易理解和维护。
我们可以这样实现封装:
class Packging{
private String secret="secret";
public String addressable="addressable";
private void fun(){
System.out.println("封装的");
}
public void pfun(){
System.out.println("公开的");
}
}
这样secret属性和fun方法就只能在Packging类中能访问到,在其他类中访问不到,这就实现了封装。
1.2、getter和setter
被private修饰的属性其他类中不能调用,但是可以使用getter和setter方法进行访问及修改。
getter方法可以对被private修饰的方法进行访问。
setter方法可以对被private修饰的方法进行修改。
我们以上面被封装的secret为例,介绍如何使用这两个方法
public class Test {
public static void main(String[] args) {
Packging packging=new Packging();
packging.getSecret();
packging.setSecret("a");
}
}
class Packging{
private String secret="secret";
public String addressable="addressable";
private void fun(){
System.out.println("封装的");
}
public void pfun(){
System.out.println("公开的");
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}
不知道你们会不会有一种想法,既然也可以通过getter和setter访问及修改,那还不如直接将其修改为public,这样还可以减少代码量,但事实不是如此,我认为有以下三个原因会存在这两个方法
- 可以在setter方法中编写一些内容,比如使用private修饰用户名,当用户想要修改用户名为傻逼等一系列敏感词,我们就可以在setter中进行拦截,不能让他修改。
- 绝大部分的Java框架、类库在使用的时候都是调用set、get方法来设置数据、获取数据。如果我们不遵守这个规则,就无法使用这些东西,那岂不是还得重复造轮子。
- 若我们有一个变量时public修饰,此时它已经在很多类中使用,而我们又向修改这个变量,岂不是要进行大量重复操作,既麻烦又容易出错,何不使用封装,直接使用setter方法修改一次即可。
二、继承
继承简单来说就是子类继承了父类的特征和行为。
图中食草动物和食肉动物就是动物的子类,动物就是食草动物和食肉动物的父类,继承关系应该符合is a ;比如食肉动物is a 动物。
那么java中如何实现继承,需要使用extends 关键字:
extends关键字
比如我们创建一个Animal类,实现一个动物都有的方法eat,在创建Cat类时使用extends继承Animal的eat方法,就不必再写一个eat方法,这样使代码更加简洁。
public class Animal {
public void eat(){
System.out.println("eat");
}
public static void main(String[] args) {
Cat cat=new Cat();
cat.eat();
}
}
class Cat extends Animal{
}
//输出结果 : eat
在java中只能单继承,也就是说Cat类如果继承了Animal类,便不可再继承其他类。继承虽然为设计带来很大的便捷,但是也不能出现多层的继承,一般继承超过三层,那么就需要考虑重构。如何防止出现多层继承?可以使用final关键字,
final关键字修饰类表示该类不能再被继承,比如上面的代码,如果我们使用final关键字修饰Animal类,再使用Cat继承Animal时就会报错。
super关键字
我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类
public class Animal {
public void eat(){
System.out.print("父类");
}
public static void main(String[] args) {
Cat cat=new Cat();
cat.tyrEat();
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.print("子类");
}
public void tyrEat(){
super.eat();
this.eat();
}
}
//输出结果:父类子类
在继承中若我们new一个子类对象,会先加载父类,再加载子类,看以下代码:
public class Animal {
public Animal(){
System.out.println("父类");
}
public void eat(){
System.out.println("父类");
}
public static void main(String[] args) {
Cat cat=new Cat();
}
}
class Cat extends Animal{
public Cat(){
System.out.println("子类");
}
}
//输出结果:父类 子类
三、多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态存在的三个条件:
- 继承
- 重写
- 父类引用指向子类对象(向上转型)
我们先来看看向上转型
向上转型
1.直接赋值
比如上述代码若有向上转型就可以写为 Animal cat=new Cat();
2.方法传参
假设我们现在还有一个Dog类继承Animal类,编写一个fun方法,调用eat方法,那么我们可能需要这样写
public class Animal {
public void eat(){
System.out.println("eat");
}
public static void main(String[] args) {
Cat cat=new Cat();
cat.fun(cat);
Dog dog=new Dog();
dog.fun(dog);
}
public static void fun(Cat cat){
cat.eat();
}
public static void fun(Dog dog){
dog.eat();
}
}
class Dog extends Animal{
}
class Cat extends Animal{
}
而如果我们使用向上转型,将fun的参数改为父类Animal animal,就不用再写重复代码:
public class Animal {
public void eat(){
System.out.println("父类");
}
public static void main(String[] args) {
Cat cat=new Cat();
cat.fun(cat);
Dog dog=new Dog();
dog.fun(dog);
}
public static void fun(Animal animal){
animal.eat();
}
}
class Dog extends Animal{
}
class Cat extends Animal{
}
3.方法返回
这个和第二个类似,若返回值类型都设计为父类,便不用再写重复类型代码。
多态实例
比如我们编写一个方法,还是eat,但是狗喜欢吃火腿肠,猫喜欢吃鱼,我们就可以这样写
public class Animal {
public void eat(){
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("喜欢吃火腿肠");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("喜欢吃鱼");
}
}
父类方法体中什么都不用写,这样一个引用,表现出多种不同的形态就叫多态。现在是不是对多态更了解了。
多态的好处
- 类调用者对类的使用成本进一步降低
- 降低代码的圈复杂度
- 可扩展能力更强
四、补充知识
向下转型
假设我们设计Bird类继承Animal类,不仅会吃,还会飞,我们这样定义 Animal bird=new Bird();那么此时我们调用bird的飞方法就会报错(因为虽然new的是Bird,但是还是属于Animal类,Animal中没有fly方法,自然会报错)。此时就需要向下转型:
public class Animal {
public void eat(){
}
public static void main(String[] args) {
Animal bird=new Bird();
bird=(Bird)bird;
//向下转型
((Bird) bird).fly();
}
}
class Bird extends Animal{
@Override
public void eat() {
System.out.println("eat");
}
public void fly(){
System.out.println("fly");
}
}
但是这样还是不保险,万一我们不知道bird原来是不是Bird类型也会报错(万一它是RedBird呢?),此时我们需要使用instanceof进行判断bird引用是不是Bird类的实例。
public class Animal {
public void eat(){
}
public static void main(String[] args) {
Animal bird=new Bird();
bird=(Bird)bird;
if(bird instanceof Bird){
((Bird) bird).fly();
}
}
}
class Bird extends Animal{
@Override
public void eat() {
System.out.println("eat");
}
public void fly(){
System.out.println("fly");
}
}
这样就保险很多啦!!!