1.继承
1)概念:
将多个类的共性内容抽取出来,放在一个单独类中,让这一个类和多个类产生一种关系"继承".
2)特点:
1)在Java语言中;类与类之间的继承关系,只支持单继承. 2)虽然类与类之间只支持单继承,但是可以多层继承.
3)格式:
class 父类名{
}
class 子类名 extends 父类名{
}
4)案例:
public class Animal {
// 属性:姓名,年龄,颜色
private String name ;
private int age ;
private String color ;
//无参构造方法
public Animal() {
}
//有参构造方法
public Animal(String name, int age, String color) {//"tomcat",10,"黄色"
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;//多啦A梦
}
public void setName(String name) {//多啦A梦
this.name = name;//多啦A梦
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//吃
public void eat(){
System.out.println("动物都需要吃饭...");
}
//睡
public void sleep(){
System.out.println("动物都需要休息...");
}
}
public class Cat extends Animal{
public Cat() {
//隐藏super();
}
public Cat(String name, int age, String color) {//"tomcat",10,"黄色"
super(name, age, color);//"tomcat",10,"黄色"
}
//特有功能:玩毛线
public void playGame(){
System.out.println("猫爱玩毛线球球...");
}
//eat方法重写
public void eat(){
System.out.println("猫吃老鼠...");
}
public void sleep(){
System.out.println("猫趴着睡觉...");
}
}
public class AnimalTest {
public static void main(String[] args) {
//测试猫
//方式1:无参构造方法+setXXX(XX)/getXXX()继承父类的
Cat cat = new Cat() ;
cat.setName("多啦A梦");
cat.setAge(5);
cat.setColor("蓝色");
System.out.println("猫的名字是:"+cat.getName()+
",年龄是:"+cat.getAge()+",毛色是:"+cat.getColor());
cat.eat() ;
cat.sleep() ;
cat.playGame(); //特有功能
System.out.println("------------------------------------------") ;
//方式2:有参构造方法+getXXX()
Cat cat2 = new Cat("tomcat",10,"黄色") ;
System.out.println("猫的名字是:"+cat2.getName()+
",年龄是:"+cat2.getAge()+",毛色是:"+cat2.getColor());
cat2.eat() ;
cat2.sleep() ;
cat2.playGame(); //特有功能
}
}
//继承 子类可以不重写方法.
5)好处:
1)提高代码的复用性. 2)调高代码的维护性格. 3)类与类产生这种关系"继承",是多态的前提条件.
6)加入继承后的成员变量的访问问题:
情况1:
子类继承父类,子类的成员变量名称和父类的成员变量名称不一致的情况:很简单,分别调用即可!
class Fu2{
//父类的成员变量
int num = 100 ;
}
//定义一个子类
class Zi2 extends Fu2{
//子类的成员变量名称和父类的成员变量名称不一致
int num2 = 200 ;
}
//测试类
public class ExtendsDemo2 {
public static void main(String[] args) {
//创建子类对象
//情况1:
Zi2 zi = new Zi2() ;
System.out.println(zi.num);
System.out.println(zi.num2);
}
}
* 情况2:
* 子类继承父类,子类的成员变量名称和父类的成员变量名称一致的情况:
* 一句话:遵循 "就近原则"
* 1)先在子类的局部位置中找,如果存在,就使用
* 2)如果不存在,那么就在子类的成员位置中找,如果存在,就使用
* 3)如果子类的成员位置中不存在,那么就在父类的成员位置中找,如果存在,就使用;
* 4)如果父类的成员位置中不存在,那么就报错了,压根不存在这个变量
class Fu2{
//父类的成员变量
int num = 100 ;
}
//定义一个子类
class Zi2 extends Fu2{
//成员方法
public void show(){
//子类的局部位置
int num = 30 ;
System.out.println(num) ;
}
}
//测试类
public class ExtendsDemo2 {
public static void main(String[] args) {
//情况2:
//创建子类对象
Zi2 zi = new Zi2() ;
zi.show() ;
}
}
7)注意事项:
最基本的注意事项:
1)子类继承父类,只能继承父类非私有的成员,私有的成员可以间接通过公共访问访问!
因为私有成员,只能在本类访问,外界类不能访问!
class Fu{
//父类有两个成员:公共的/私有的
public int num = 40 ;
private int num2 = 100 ;
//提供一个公共的成员方法
public void method(){
System.out.println(num2);
}
//私有的成员方法
private void function(){
System.out.println("function Fu...");
}
//公共的方法
public void function2(){
function();
}
}
//子类
class Zi extends Fu{
//定义一个成员方法
public void show(){
//展示数据
System.out.println(num);
// System.out.println(num2);//num2变量私有的
}
}
//测试类
public class ExtendsDemo1 {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
z.show() ;
z.method();
//z.function() ;//function方法 private 修饰了
z.function2();
}
}
2)子类继承父类,不能继承父类的构造方法,但是可以通过super访问(super重点关键字)
如何访问:
* 子类的所有构造方法都要(默认)访问父类的无参构造方法
* 因为存在继承关系,子类的构造方法可能会用到父类的数据,所以需要让父类先初始化(构造方法),然后子类在进行初始化
* ---->分层初始化
*
* 在子类的所有构造方法中第一句话:super() ; 访问父类的无参构造方法
//定义一个父类
class Fu {
//先提供父类的无参构造方法
public Fu(){
System.out.println("Fu的无参构造方法...") ;
}
}
//定义一个子类
class Zi extends Fu{
//子类的无参构造方法
public Zi(){
//super(); //可以省略不写,默认的!
System.out.println("Zi的无参构造方法...") ;
}
//提供子类的有参构造方法
public Zi(String name){
//super() ;//可以省略不写,默认的!
System.out.println("Zi的有参构造方法...");
}
}
//测试类
public class ExtendsDemo1{
public static void main(String[] args) {
//创建子类对象
Zi zi = new Zi() ;
System.out.println("----------------------------") ;
Zi zi2 = new Zi("hello") ;
}
}
结果:
Fu的无参构造方法...
Zi的无参构造方法...
----------------------------
Fu的无参构造方法...
Zi的有参构造方法...
2)this和super的区别
* super:代表父类的空间标识(父类对象的地址值引用)
* this:代表当前类对象的地址值引用
*
* 访问区别
* 访问成员变量:
* this.变量名 :访问当前类的成员变量
* super.变量名;访问的父类的成员变量
*
* 访问构造方法:
* this() ; 访问当前类的无参构造方法
* super() ; 访问的是父类的无参构造方法
*
* this(xx) ; 访问的是当前类的有参构造方法
* super(xx) ; 访问的是父类的有参构造方法
*
* 访问成员方法
* this.方法名() ; 访问的是当前类的成员方法
* super.方法名() ;访问的是父类的成员方法
8).继承中构造方法的访问问题
子类继承父类,不能继承父类的构造方法,但是可以通过super访问.
.子类的所有构造方法都要(默认)访问父类的无参构造方法.
因为存在继承关系,子类的构造方法可能会用到父类的数据,所以需要让父类先初始化(构造方法),然后子类在进行初始化;在子类所有构造方法中第一句话:super() :访问父类的无参构造方法
9).面试题:开发中什么时候使用继承?
如果B类是A类的一种,或者A类是B类一种,这个时候就可以使用继承,继承是一种"is a"的关系.
7.继承的弊端:
因为存在关系,类与类之间就存在耦合性!
考虑:
开发的设计原则:
低耦合,高内聚
耦合:类与类之间的关系
低耦合:关系越简单越好,否则.如果继承关系的多,一个父类的存在问题,其他类出现问题!
内聚:指的是执行某件事情的能力!
一个类能解决的尽量使用一个类完成
7.方法重写(覆盖)
7.1方法重写概念
子类继承父类的时候,子类中出现了和父类一模一样的方法声明,子类的功能将父类的功能覆盖掉,使用自己的业务功能完成.
7.2方法覆盖原则
(1)方法名称,参数列表,返回值类型必须与父类相同.
(2)访问修饰符与父类相同或比父类更宽泛.
7.3方法重载与方法重写区别
(1)方法重载:overload:多个方法名称相同,形式参数列表不同,与返回值无关,目的:为了提高功能扩展性.
(2)方法重写:override:子类继承父类的时候,子类出现了 和父类一模一样的方法声明;目的:使用子类的功能将父类的功能覆盖掉.
8.final关键字:
a)概念:
当父类中的功能不能让子类覆盖时,Java提供了一个关键字final:最终的,无法修改的最终的(状态修饰符)
b)案例:
需求:
* 有一个父类,父类中有一个show方法,子类继承父类,将show方法进行复写(重写)
*但是有的时候,父类的功能不能让子类覆盖,Java提供了关键字:final
*/
//父类
class Fu{
public final void show(){
System.out.println("这是一个绝密文件,任何不得更改...") ;
}
}
//子类
class Zi extends Fu{
//重写
/*public void show(){ //此时子类的不能父类的这个方法,因为父类的方法已经加入final修饰
System.out.println("这是一堆垃圾...") ;
}*/
}
//测试类
public class FinalDemo {
public static void main(String[] args) {
//创建子类对象
Zi zi = new Zi() ;
zi.show() ;
}
}
d)特点:
* 1)可以修饰类,该类不能被继承,它不能在进行扩展了...
* 举例:后面常用类中重要的类String: 被final修饰
* 2)可以修饰变量,此时这个变量是一个常量:自定义常量
*
* 3)可以修饰成员方法,此时这个方法不能被重写
***了解***
final的应用场景 (扩展)
* 自定义常量使用居多;
* final会结合static一块使用(static修饰:可以类名直接调用)
*
* public static final int num = 100 ; //修饰基本数据类型 :编译时期常量 (Jvm不需要加载)
*
* //Integer:int类型的包装类类型(引用类型)
* public static final Integer i = new Integer() ;//修饰的引用数据类型 :运行时期常量(JVM需要加载类)
*
*
e)final修饰基本数据类型和修饰引用数据类型的区别
(1)修饰基本数据类型
修饰的基本数据类型:基本数据类型的值不能在改变,只能赋值一次,不能在赋值了;此时这种常量称为"编译时期常量",Jvm只是检查语法,不需要加载.
(2)修饰引用数据类型
修饰的引用数据类型:引用数据类型的空间地址值不能在改变,但是里面的成员变量(没有加入final),依然可以访问这种常量,Jvm加载引用数据类型,属于"运行时期常量"!
4)注意****
被final修饰的变量:只能赋值一次,不能在赋值!常量,常驻内存.