一、继承
-
继承特点:
1)在Java中,类与类之间的继承关系,只支持单继承,不支持多继承!
在别的语言中,可能支持多继承,class 子类名 extends 父类名1,父类名2,…{}2)在Java中,类与类之间虽然不能 多继承,但是可以 多层继承!
举例:
class GrandFather{
public void function(){
System.out.println("我是爷爷...") ;
}
}
class Father extends GrandFather{
public void method(){
System.out.println("我是老子...") ;
}
}
/*
class Month{
}
*/
//子类
//class Son extends Father,Monther{} 多继承:Java语言中:类与类之间不支持
//正常的写法:单继承
class Son extends Father{
public void show(){
System.out.println("我是仔仔...") ;
}
}
//测试类
class ExtendsDemo{
public static void main(String[] args){
//创建子类对象
Son son = new Son() ;
son.show() ;
son.method() ;
son.function() ;
}
}
-
继承中的关系问题:
在继承中,成员变量访问问题!1)子类继承父类,如果子类的成员变量名称和父类的成员变量名称不一致的情况:
比较简单,分别访问即可2)子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致的情况:
a)现在本类的局部位置找,有没有这个变量,如果有就直接使用
b)如果本类的局部位置没有,在本类的成员位置中找,如果有,就使用
c)如果本类的成员位置没有,在它的父类的成员位置找,如果有,就使用
d)父类的成员位置都没有这个变量,压根不存在,就报错!遵循一个原则:“就近原则”
举例:
//父类
class Fu{
int num = 100 ;//父类的成员变量
}
//子类
class Zi extends Fu{
//int num2 = 200 ;
//int num = 200 ; //子类的成员变量
//成员方法
public void show(){
//int num = 50 ;
System.out.println(num) ;
}
}
//测试类
class ExtendsDemo2{
public static void main(String[] args){
//创建子类对象
Zi zi = new Zi() ;
//System.out.println(zi.num) ;
//System.out.println(zi.num2) ;
zi.show() ;
}
}
-
继承中的构造方法的访问:
继承关系中,构造方法的访问子类继承父类,不能够继承构造方法,但是可以通过super()(等会讲)间接访问父类的构造方法,让父类先进行初始化
子类的所有构造方法都默认访问父类的无参构造方法:子类的每一个构造方法的第一句话:super();
super:代表的是否父类的空间标识(代表父类的对象的地址值引用)
为什么要去让父类初始化呢?
因为子类继承父类,
可能会使用到父类的数据!所有必须先让父类初始化,然后子类在初始化(分层初始化)在写父类的时候:在继承中由于存在默认的访问问题,建议永远给出父类的无参构造方法
举例:
//子类
class Zi extends Fu{
public Zi(){
//隐藏,可以不写
//super() ;
System.out.println("这是子类的无参构造方法...") ;
//super() ; //要显示 super,必须在第一句话
}
public Zi(String name){
//super() ;
System.out.println("这是子类的有参构造方法") ;
}
}
//测试类
class ExtendsDemo3{
public static void main(String[] args){
//创建子类对象
Zi zi = new Zi() ; //无参构造方法
System.out.println("------------------") ;
Zi zi2 = new Zi("hello") ; //子类有参构造方法
}
}
- 继承练习
举例1:
/*
面试题
子类继承父类,那么如果父类的无参构造方法没有,子类的构造方法会出现什么问题,以及
如果存在问题,如何解决?
子类的所有构造方法都会报错:存在默认访问:子类的所有构造方法都默认访问父类的无参(第一句:super())
解决办法:
1)手动给出父类的无参构造方法
2)在子类的所有构造方法中,间接通过super(xx):访问父类的有参构造方法
3)子类的所有构造方法的一个只要能够让父类初始化即可!(不推荐的!)
执行子类无参构造方法,先执行本的有参构造方法:this(xx)
然后在通过本类的有参构造方法 :super(xx):间接访问父类的有参构造,完成父类初始化
*/
//父类
class Fu{
/*
public Fu(){
}
*/
public Fu(String name){
System.out.println("这是父类的有参构造方法") ;
}
}
//子类
class Zi extends Fu{
public Zi(){
//super("随便给") ; //访问父类的有参构造
this("hello") ; //本类的有参构造方法
System.out.println("这是子类的无参构造方法...") ;
}
public Zi(String name){
super("随便给") ;//访问父类的有参构造
System.out.println("这是子类的有参构造方法") ;
}
}
//测试类
class ExtendsDemo4{
public static void main(String[] args){
Zi zi = new Zi() ;
System.out.println("-------------------") ;
Zi zi2 = new Zi("javaee") ;
}
}
```:
```java
举例2:
/*
猫狗案例---->继承版
猫存在属性:
姓名,年龄,颜色
行为:
吃,睡,玩游戏
狗存在 属性:
姓名,年龄,颜色
行为
吃,睡,看门
将两个事物的共性内容抽取在一个独立的类中:
动物事物
属性:姓名,年龄,颜色 属性私有化
行为:吃,睡
公共访问方法:setXXX()/getXXX()
猫事物 和狗事物分别继承自动物,
在每一个具体的事物中:提供对应的构造方法...
定义动物类,猫类和狗类,分别测试
*/
//定义一个动物类
class Animal{
//姓名,年龄,颜色 属性私有化
private String name ;
private int age ;
private String animalColor ;
//父类的无参构造方法
public Animal(){
}
//有参构造方法
public Animal(String name,int age,String animalColor){
this.name = name ;
this.age = age ;
this.animalColor = animalColor ;
}
//公共访问方法
public void setName(String name){
this.name = name ;
}
public String getName(){
return name ;
}
public void setAge(int age){
this.age = age ;
}
public int getAge(){
return age ;
}
public void setAnimalColor(String animalColor){
this.animalColor = animalColor ;
}
public String getAnimalColor(){
return animalColor ;
}
//其他成员方法:吃,睡
public void eat(){
System.out.println ("动物饿了就需要吃饭...") ;
}
public void sleep(){
System.out.println ("动物困了都需要休息...") ;
}
}
//猫类 继承自动物类
class Cat extends Animal{
//无参构造方法
public Cat(){
//super() ; //省略
}
//子类的有参构造
public Cat(String name,int age,String animalColor){ //"tom",5,"蓝色"
super(name,age,animalColor) ; //访问父类的有参构造方法
}
//子类的特有功能
public void playGame(){
System.out.println("猫完毛线...") ;
}
}
//狗类
class Dog extends Animal{
//无参构造方法
public Dog(){
//super() ; //省略
}
//子类的有参构造
public Dog(String name,int age,String animalColor){ //"小白",3,"白色"
super(name,age,animalColor) ; //访问父类的有参构造方法
}
//特有功能
public void lookDoor(){
System.out.println("狗可以看家...") ;
}
}
//测试类
class ExtendsTest{
public static void main(String[] args){
//测试狗类
//方式1:无参构造+setXXx()
Dog d = new Dog() ;
d.setName("小白") ;
d.setAge(3) ;
d.setAnimalColor("白色") ;
System.out.println("当前狗的姓名是:"+d.getName()+",年龄是:"+d.getAge()+",颜色是:"+d.getAnimalColor()) ;
d.eat() ;
d.sleep() ;
d.lookDoor() ;
System.out.println("----------------------------") ;
//方式2:有参构造+getXXX()
Dog d2 = new Dog("旺财",5,"黑色") ;
System.out.println("当前狗的姓名是:"+d2.getName()+",年龄是:"+d2.getAge()+",颜色是:"+d2.getAnimalColor()) ;
d2.eat() ;
d2.sleep() ;
d2.lookDoor() ;
//猫类自己 测试
}
}
举例3:
//看程序,写结果
//需求:最终输出的结果:30,20,10
/*
考点:继承关系中,成员变量访问问题 :如果子类继承父类,成员变量名称都一致, 就近原则
需要现在子类的局部位置找,有就使用
没有,在子类的成员位置找,有就使用
没有,在父类的成员位置找,有就使用
this和super的区别
this:代表的本类对象的地址值引用
super:代表的父类空间标识(父类对象的地址值引用)
this.变量:访问的本类的成员变量
this.方法名():访问的本类的成员方法
this()/this(xx):访问本类的无参构造方法/访问的本类的有参构造方法
super.变量名:访问的是父类的成员变量
super.方法名():访问的父类的成员方法
super()/super(xx):访问的父类的无参构造方法/访问的父类的有参构造方法
*/
//父类
class Fu{
int num = 10 ;
}
//子类
class Zi extends Fu{
int num = 20 ;
public void show(){
int num = 30 ;
//补全代码
System.out.println(num) ;
System.out.println(this.num) ;
System.out.println(super.num) ;
}
}
class Test{
public static void main(String[] args){
Zi zi = new Zi() ;
zi.show() ;
}
}
举例4:
//看程序,写结果
/*
考点:
1) 继承中的分层初始化
子类继承父类
Zi zi = new Zi() ;-- 子类的构造方法: class Zi extends Fu{}
需要让父类先初始化----先执行父类构造方法,然后才是子类的构造方法!
2)
继承关系中,成员变量访问问题 :如果子类继承父类,成员变量名称都一致, 就近原则
需要现在子类的局部位置找,有就使用
没有,在子类的成员位置找,有就使用
没有,在父类的成员位置找,有就使用
this和super的区别
this:代表的本类对象的地址值引用
super:代表的父类空间标识(父类对象的地址值引用)
this.变量:访问的本类的成员变量
this.方法名():访问的本类的成员方法
this()/this(xx):访问本类的无参构造方法/访问的本类的有参构造方法
super.变量名:访问的是父类的成员变量
super.方法名():访问的父类的成员方法
super()/super(xx):访问的父类的无参构造方法/访问的父类的有参构造方法
*/
class Fu{
int num = 100 ;
public Fu(){
System.out.println("Fu...") ;
}
}
class Zi extends Fu{
int num = 200 ;
public Zi(){
System.out.println("Zi...") ;
}
public void method(){
int num = 300 ;
System.out.println(num) ;
System.out.println(this.num) ;
System.out.println(super.num) ;
}
}
class Test2{
public static void main(String[] args){
Zi zi = new Zi() ;
zi.method() ;
}
}
举例5:
//看程序,写结果
/*
Person的静态代码块
Student的静态代码块
Person的构造代码块
Person的无参构造方法
Student的构造代码块
Student的无参构造方法
--------
Person的构造代码块
Person的无参构造方法
Student的构造代码块
Student的无参构造方法
考点:
1)继承的:分层初始化
2)代码块的优先级
*/
class Person{
static{
System.out.println("Person的静态代码块") ;
}
public Person(){
System.out.println("Person的无参构造方法") ;
}
{
System.out.println("Person的构造代码块") ;
}
}
class Student extends Person{
static{
System.out.println("Student的静态代码块") ;
}
public Student(){
System.out.println("Student的无参构造方法") ;
}
{
System.out.println("Student的构造代码块") ;
}
}
//测试类
class Test3{
public static void main(String[] args){
Student s = new Student() ;
System.out.println("--------") ;
Student s2 = new Student() ;
}
}
二、方法重载override
方法重写:override,父类继承子类,出现了与父类一模一样的方法声明权限修饰符,方法名、返回值类型、形参列表都相同,方法覆盖为了将父亲的功能覆盖掉,为了使用子类自己的功能。
举例:
public void eat(){
System.out.println("人只能吃饭!");
}
public void eat(){
System.out.println("动物可以吃shit!");
}
方法重载:overload,定义方法的时候,如果多个方法名相同,形式参数列表不同,与返回值无关。可以提高代码的扩展性,可以针对同一功能传递不同类型的参数。(参数列表不同,参数类型不同。)
public boolean compare (int a,int b){}
public boolean compare(float a,float b){}
三、final关键字
-
final:子类继承父类的时候,有时需要将父类的功能覆盖掉,完成自己的功能,但是,有时候不能覆盖!现在不想让父类的功能被覆盖掉,使用final关键字:状态修饰符。
(最终的,无法更改的,状态修饰符)
1). 可以修饰类,该类不能被继承;
2).可以修饰变量,此时这个变量是一个常量:自定义常量
此时这个变量只能被赋值一次,再次赋值,报错!
3).可以修饰方法,此时这个方法不能被重写! -
final关键字修饰基本类型/引用类型的区别:
当final修饰基本数据类型,值不能再改变,只能赋值一次!
当final修饰引用数据类型,引用类型地址值不能再改变! -
final关键字的特点有哪些:
final:状态修饰符,可以修饰类:该类不能被继承可以修饰变量,此时这个变量是常量,只能被赋值一次,不能再次更改了!
成员位置:
public static final int xx = 值; 传统方式定义常量 普通格式(编译时期常量)
public final Student s = new Student() ; //实例(创建对象)变量 (运行时期常量)修饰方法,此方法不被重写!
四、IDEA