JAVA中方法的声明及使用方式(继承、多态、封装)
作者:小新的编程之路
一、写在前面
今天就来总结一下JAVA中方法的声明及使用,即继承、多态、封装。
其实关于三大特性对于学习JAVA的同学来说都是基本的了,毕竟只要接触Java这些都是先要认识的,接下来就系统总结一下。
二、继承
先来说说继承,所谓继承本质就是实现代码的复用,防止重复的代码多次书写,当一个类继承一个类的时候,该类中就会拥有另外一个类中的所有代码
2.1 继承的注意事项
只支持单继承,即一个子类只允许有一个父类,但是可以实现多级继承,及子类拥有唯一的父类,而父类还可以再继承。
子类可以拥有父类的属性和方法。
子类可以拥有自己的属性和方法。
子类可以重写覆盖父类的方法。
2.2 继承的特点
- 提高代码复用性。
- 父类的属性方法可以用于子类。
- 可以轻松的定义子类。
- 使设计应用程序变得简单。
2.3 继承的使用
1,在父子类关系继承中,如果成员变量重名,则创建子类对象时,访问有两种方式。
a:直接通过子类对象访问成员变量
List item
等号左边是谁,就优先使用谁,如果没有就向上找。
b:间接通过成员方法访问成员变量
该方法属于谁,谁就优先使用,如果没有就向上找。
public class FU { int numFU = 10; int num = 100; public void method(){ System.out.println("父类成员变量:"+numFU); } public void methodFU(){ System.out.println("父类成员方法!"); } } public class Zi extends FU{ int numZi = 20; int num = 200; public void method(){ System.out.println("子类成员变量:"+numFU); } public void methodZi(){ System.out.println("子类方法!"); } }
public class ExtendDemo { public static void main(String[] args) { FU fu = new FU(); // 父类的实体对象只能调用父类的成员变量 System.out.println("父类:" + fu.numFU); // 结果:10 Zi zi = new Zi(); System.out.println("调用父类:" + zi.numFU); // 结果:10 System.out.println("子类:" + zi.numZi); // 结果:20 /** 输出结果为200,证明在重名情况下,如果子类中存在则优先使用, * 如果不存在则去父类查找,但如果父类也没有那么编译期就会报错。 */ System.out.println(zi.num); // 结果:200 /** * 通过成员方法调用成员变量 */ zi.method(); // 结果:10 } }
2,同理:
成员方法也是一样的,创建的对象是谁,就优先使用谁,如果没有则直接向上找。
注意事项:
无论是成员变量还是成员方法,如果没有都是向上父类中查找,绝对不会向下查找子类的。
3,在继承关系中,关于成员变量的使用:
- 局部成员变量:直接使用
- 本类成员变量:this.成员变量
- 父类成员变量:super.父类成员变量
int numZi = 10; public void method() { int numMethod = 20; System.out.println(numMethod); // 访问局部变量 System.out.println(this.numZi); // 访问本类成员变量
2.4 重写和重载
2.4.1 重写(override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。
即外壳不变,核心重写!
class Animal{ public void move(){ System.out.println("动物行走!"); } } class Dog extends Animal{ public void move(){ System.out.println("狗可以跑和走"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); // Animal 对象 Animal b = new Dog(); // Dog 对象 a.move();// 执行 Animal 类的方法 b.move();//执行 Dog 类的方法 } }
重写的规则:
1,参数列表必须与被重写方法相同。
2,访问权限不能比父类中被重写的方法的访问权限更低(public>protected>(default)>private)。
3,父类成员的方法只能被它的子类重写。
4,被final修饰的方法不能被重写。
5,构造方法不能
2.4.2 重载(overload)
重载是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
public class Overloading { public int test(){ System.out.println("test1"); return 1; } public void test(int a){ System.out.println("test2"); } //以下两个参数类型顺序不同 public String test(int a,String s){ System.out.println("test3"); return "returntest3"; } public String test(String s,int a){ System.out.println("test4"); return "returntest4"; } public static void main(String[] args){ Overloading o = new Overloading(); System.out.println(o.test()); o.test(1); System.out.println(o.test(1,"test3")); System.out.println(o.test("test4",1)); } }
重载规则:
1,被重载的方法必须改变参数列表(参数个数或者类型不一样)。
2,被重载的方法可以改变返回类型。
3,被重载的方法可以改变访问修饰符。
2.4.3 this,super关键字
super()关键字的用法:
- 子类的成员方法中,访问父类的成员变量。
- 子类的成员方法中,访问父类的成员方法。
- 子类的构造方法中,访问父类的构造方法。
this关键字用法:
- 本类成员方法中,访问本类的成员变量。
- 本类成员方法中,访问本类的另一个成员方法。
- 本类的构造方法中,访问本类的另一个构造方法。
注意:
this关键字同super一样,必须在构造方法的第一个语句,且是唯一的。
this与super不能同时存在。
2.4.4 补充概念
隐藏
父类和子类拥有相同名字的属性或者方法( 方法隐藏只有一种形式,就是父类和子类存在相同的静态方法)时,父类的同名的属性或者方法形式上不见了,实际是还是存在的。
隐藏是对于静态方法和成员变量(静态变量和实例变量)而言的
public class Animal { String name; int age; int legs; public void eat(){ System.out.println("动物要吃饭"); }; //类方法,静态方法 //通过类就可以直接调用 public static void run(){ System.out.println("动物在奔跑"); } } public class Cat extends Animal { //重写父类方法 public void eat() { System.out.println("小猫吃鱼"); } //隐藏父类的run方法 public static void run(){ System.out.println("小猫在奔跑"); } }
对象转型
引用类型和对象类型不一致的情况下的转换问题
子类转父类(向上转型)
Animal a = new Animal(); Cat c = new Cat(); a = c;
一个很简单的判别办法,把右边的当做左边来用,看说得通不。右边c引用所指向的对象的类型是 猫
左边a引用的类型是 普通动物,把猫 当做 普通动物,说不说得通? 说得通,就可以转
父类转子类(向下转型)
父类转子类,有的时候行,有的时候不行,所以必须进行强制转换。强制转换的意思就是 转换有风险,风险自担。
可以的情况
Animal a = new Animal(); Cat c = new Cat(); a = c; c = (Cat) a; 不可以的情况 Animal a = new Animal(); Cat c = new Cat(); Dog d = new Dog(); a = d; c = (Cat) a; 没有继承关系的两个类,互相转换
没有继承关系的两个类,互相转换,一定会失败。
虽然Cat和Dog都继承了Animal,但是彼此没有互相继承关系
- 实现类转换成接口(向上转型)
- 接口转换成实现类(向下转型)
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。
如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
三、多态
3.1 定义和优点
定义:
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态就是同一个接口,使用不同的实例而执行不同操作。
优点:
- 1. 消除类型之间的耦合关系;
- 2. 可替换性;
- 3. 可扩充性;
- 4. 接口性;
- 5. 灵活性;
- 6. 简化性;
3.2 多态的体现形式
继承父类引用指向子类重写
注意:在多态中,编译看左边,运行看右边
public class MultiDemo { public static void main(String[] args) { // 多态的引用,就是向上转型 Animals dog = new Dog(); dog.eat(); Animals cat = new Cat(); cat.eat(); // 如果要调用父类中没有的方法,则要向下转型 Dog dogDown = (Dog)dog; dogDown.watchDoor(); } } class Animals { public void eat(){ System.out.println("动物吃饭!"); } } class Dog extends Animals{ public void eat(){ System.out.println("狗在吃骨头!"); } public void watchDoor(){ System.out.println("狗看门!"); } } class Cat extends Animals{ public void eat(){ System.out.println("猫在吃鱼!"); } }
例如:
在设计房子时,大门的设计应该开进不同型号车辆,如打开一扇门,可以开进摩托车;打开两扇门,可以开进小汽车;如果需要,打开三扇门,允许开进货车等。
同样是门,由于不同参数,可以完成不同的功能,这个门具有多态性。
3.3 向上转型
- 格式:父类名称 对象名 = new 子类名称();
- 含义:右侧创建一个子类对象,把它当作父类来使用。
- 注意:向上转型一定是安全的。
- 缺点:一旦向上转型,子类中原本特有的方法就不能再被调用了。
四、封装
4.1 封装的特性
在面向对象程式设计方法中,封装(Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问;要访问该类的代码和数据,必须通过严格的接口控制;封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段;适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的特点
- 对成员变量实行更准确的控制。
- 封装可以隐藏内部程序实现的细节。
- 良好的封装能够减少代码之间的耦合度。
- 外部成员无法修改已封装好的程序代码。方便数据检查,有利于保护对象信息的完整性,同时也提高程序的安全性。便于修改,体高代码的可维护性。
4.2 封装的实现
使用private修饰符,表示最小的访问权限。
对成员变量的访问,统一提供setXXX,getXXX方法。
下面请看一个Student实体对象类:
public class Student implements Serializable { private Long id; private String name; private Integer sex; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } }
分析:对于上面的一个实体对象,我想大家都已经很熟悉了。将对象中的成员变量进行私有化,外部程序是无法访问的。但是我们对外提供了访问的方式,就是set和get方法。
而对于这样一个实体对象,外部程序只有赋值和获取值的权限,是无法对内部进行修改,因此我们还可以在内部进行一些逻辑上的判断等,来完成我们业务上的需要。
到这里应该就明白封装对于我们的程序是多么重要。下面再来说说继承的那点事。
修改属性的可见性来限制对属性的访问(一般限制为private),例如
```java public class People { //将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。 private String name; private int age; }
对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class People{ //采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。 private String name; private int age; public String getName(){ return name; } public void setName(String name){ this.name = name; } }
4.3 成员的访问权限
Java提供了三个访问控制符:private、protected和public,分别代表三个访问控制级别。
default访问控制权限(包访问权限)
如果类里的一个成员不使用任何访问控制符修饰,则使用default默认访问控制,default访问控制的成员可以被相同包下其他类访问。
protected访问控制权限(子类访问权限)
如果一个成员使用protected访问控制符修饰,那么这个成员即可以被同一包中其他类访问,也可以被不同包中的子类访问。
public访问控制权限(公共访问权限)
如果一个成员使用public访问控制符修饰,则可以被所有类访问。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。