java学习笔记(7)【构造方法/static关键字/代码块/继承/多态】


提示:以下是本篇文章正文内容,下面案例可供参考

Day12

1.构造方法(Constructor)

总结:

​ 构造方法是方法,但是是一个特殊的方法

特殊性

​ ① 构造方法的方法名和类名相同
​ ② 没有具体的返回值类型 (连void都没有)
​ ③ 在方法中不能使用return语句返回一个值,但是可以单独写return语句来作为方法的结束!

构造方法的目的
​ 就是给成员变量赋值!

构造方法是可以重载的!

给成员变量赋值的方式:

​ setxxx(局部变量)方法
​ 有参构造方法(局部变量…)

构造方法使用的注意事项:

​ ① 构造方法中,没有返回值类型的,连void都没有,不能随意定义构造方法!

② 当前我们写的类(非测试类)中,没有提供任何构造方法的时候
​ 系统默认会给我们提供无参构造方法,以后永远给出"无参构造方法",继承中就会遇到@

③ 如果我们给了其中的有参构造方法,此时系统不会再提供无参构造方法,那么使用无参方法new对 象的话,就会报错!这也是为什么永远无法给出无参构造方法的原因之一

给成员变量数据初始化

​ ① 通过无参构造方法 + setxxx()赋值,通过getxxx()获取值
​ ② 通过**有参构造方法直接赋值,**getxxx()获取值

2.static关键字(重点)

java提供而关键字"static" 
			static是静态修饰符---->最基本的概念:就是可以被多个对象"共享,共用!"
			
			静态的东西都是随着类的加载而加载,优先于对象存在!
			
static关键字的特点:
	1)	被static关键字修饰的变量或者方法---都叫做"类变量/类方法"
		因为他们是随着类的加载而加载,优先于对象先存在的!
	2)	static不能喝this共存!
			this:代表的当前类对象的地址值引用 ---创建对象了
				this.变量名:访问当前类的成员变量---非静态的
				this.方法名();访问当前类的成员方法---非静态的
				
			static:是要优先于对象存在,两者不能共存(生命周期不同!)
	3)static基本的特点:
				共享共用,告诉我们/需求体现共享共用,可以使用static修饰!
	4)被静态修饰的变量/方法.推荐的访问方式(重点)
	
		类名.变量名 ;
		类名.方法名() ;
		
注意事项:非静态的成员方法,既可以访问静态的,也可以访问非静态的
		静态的方法:只能访问静态的东西(静态变量/里面调用都是静态方法)
		
		
		静态只能访问静态!!!!!!
		

3.代码块(了解)

必须要知道执行顺序:一般都出现笔试题中(选择题)


代码块:在java中使用{}包裹起来的就是代码块
   分类:
           局部代码块:
           				在方法定义中的{},作用:限定变量的生命周期
           
           构造代码块:
           			在类的成员位置(类中方法外),{},作用:可以对成员的数据进行初始化
                     特点:如果一个类中有构造代码快,先执行的是构造代码块,然后执行构造方法
                   	
                   	构造代码块的优先级高于构造方法 (重点) (开发中很少见构造代码块,笔试题中出现多)
             静态代码块:
                       格式:
                             static{

                              }

                       静态的东西---优先于对象存在,那么静态代码块也一样,先执行
                        由于类就加载一次,所以静态代码块也就执行一次!!!
 
                优先级:   静态代码块>构造代码块>构造方法
 
 
  每次执行构造方法之前,如果存在构造代码块都要先执行构造代码块!!!

4.继承(重点)

继承:
      将多个类的共享内容抽取出来放在一个独立的类中,那么这个独立的类和这多个类产生的关系----继承关系 ,关键字extends
 格式:
      class 父类名{}
                 class 子类名 extends 父类名{
                 }

 继承的好处:
      1)提高了代码的复用性
      2)提供了代码的维护性
      3)类与类之间的继承关系,是"多态"的前提条件

Day13

1.this和super的区别

this:代表当前类对象的地址值引用
​ Student s = new String() ; //空间地址值

super:代表的父类的空间标签(父类对象的地址值引用)

访问变量:

​ this.变量名; : 访问当前类中的成员变量
​ super.变量名; : 访问父类中的成员变量

访问成员方法:

​ this.方法名() ; 访问当前类中的成员方法
​ super.方法名() ; 访问父类中的成员方法

访问构造方法:

​ this() ; 访问的当前本类的无参构造方法
​ this(xxx); 访问的是当前类的有参构造方法

​ super(); 访问的父类的无参构造方法
​ super(xxx); 访问的父类的有参构造方法

2.方法的重写和方法重载的区别

Override 和 Overload 的区别

方法重写

继承关系中,子类出现了的父类一模一样的方法(权限修饰符,方法名,参数列表都相同)
子类将父类的方法覆盖了 ;

方法重载
在定义方法的时候,方法名相同,参数列表不同(参数类型,参熟个数,类型的顺序),与返回值无关 ;

重载的目的
是为了提高某个功能的扩展性,同样一个功能,可以传递不同类型的参数

3.final关键字的特点

final:最终的,无法更改的,状态修饰符
修饰字符,类不能被继承
修饰成员方法,该方法不能被重写
修饰成员变量,此时变量是一个常量

final 修饰的基本数据类型,基本数据类型的数据值不能再赋值了
final修饰引用数据类型,当前类不能再去new对象了
final Student s = new Student() ; //s地址值是当前的地址,不能再重新new了

4.继承中的构造方法如何访问?

子类不能继承父类的构造方法,是通过super访问父类的构造方法
当前子类继承父类的时候,子类的所有构造方法都默认的访问父类的无参构造方法
当前如果没有给出父类无参构造方法时,子类就会出现问题:

​子类的所有构造方法都报错,如何解决呢?

​1)手动给出父类的无参构造方法
​2)间接访问父类的有参构造方法

5.继承中成员变量方法名一致.如何访问?

就近原则:

​ 1)先在子类的局部位置中找,局部位置有就使用
​ 2)局部位置没有,在子类的成员位置中找,有就使用
​ 3)如果子类成员位置没有,在父类中成员位置中找,有就使用
​ 4)如果在父类的成员位置中找不到,就报错了,不存在!

Day14

1.什么是多态?

一个事物在不同时刻体现的不同形态(水/冰/气)

微观角度考虑: 内存中的变化

多态的前提条件是什么:
​ 1)继承关系,必须存在,没有继承关系----谈不上多态
​ 2)必须存在方法重写,因为子类需要覆盖父类的功能
​ 3)必须有父类引用指向子类对象----->称为"向上转型"

//3)的书写格式:	向上转型
class Fu{}
class Zi extends Fu{
    //方法重写
}

	Fu fu  = new Zi() ;

2.多态的成员访问特点(重点):

1)成员变量(非静态)
编译看左,运行看左

2)成员方法(非静态)
编译看左,运行看右
子类的方法将父类的方法覆盖了,所有使用的子类的功能

class Fu{
	int num = 100 ;
	
	public void show(){
		System.out.println("打印出Fu") ;
	}                        
}
class Zi extends Fu{
    int num = 20 ;
    //方法重写
    public void show(){
        System.out.println("打印出Zi");
    }
}     
                           
  //测试类
 class  DuoTaiDemo{
     public static void main(String[] args){
         //父类引用指向子类对象---"向上转型"
         Fu fu =  new  Zi();
         //向上转型用的是都是父亲的东西,内存中用的是子类
         //new的是子类,但是用的是父类的东西---->体现了"编译看左,运行看左"
         
         //那么下面打印的是多少?
         System.out.println("fu.num");//------>100  运行时还看得是父亲的
         //编译没有报错,说明Fu类型中有num变量----->如果没有num变量,就会报错
         
         //如果没有存在方法重写,打印的就是"打印出Fu"
         //现在重写了,打印出的就是"打印出Zi"
         fu.show() ;//打印出来的是多少?
         
         
     }
 }                          


3)静态方法算不上方法重写----跟类相关,类名.方法名()
编译看左,运行看左

//继续上面的代码
//在父类和子类中分别定义一个静态的方法
public static void method(){
	//在父类中输出
    System. out.println("method Fu");
    //在子类中输出
    System. out.println("method Zi");
}

//测试类中
Fu.method();//----静态方法是通过类名访问的--非得访问--使用对象名来访问也可以,但是不建议!
Zi.method();//静态方法就不叫重写!


4)构造方法------访问-----由于多态还是需要继承的,所以分层初始化

//继续在代码中加入构造方法
//在父类中
public Fu(){
	System.out.println("Fu的无参构造方法");
}

//在子类中
public Zi(){
    //super()---隐藏了 可以不写
    System.out.println("Zi的无参构造方法") ;
}


//最终结果
//Fu的无参构造方法
//Zi的无参构造方法

3.多态的好处是什么?

1)提高代码的复用性(由继承保证)
2)提高代码的扩展性(有多态保证:父类引用指向子类对象)

多态是经常使用的,几乎所有java源代码里面都有多态(重点)

//Person类和Student类
public void method(Student s){//传递实际参数需要Student的具体对象

}
//那么现在可以这样
public void method(Person s){//这样就体现了提高代码的扩展性
				//Person类型(父类)---子类是Student(那么就可以new 子类对象)
    			//new Person没什么意义,因为存在方法重写,会被覆盖
				//传递实际参数需要Person类的子类对象
				//Person p = new Student() ;

}

理解如下代码:

//有一个动物类
class Animal{
    public void eat(){
        System.out.println("动物都需吃");
    }
    public void sleep(){
        System.out.println("动物都需睡");
    }
}
//子类
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫躺着睡觉");
    }
}
class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void sleep() {
        System.out.println("狗趴着睡觉");
    }
}

//测试类
public class DuoTaiDemo2 {
    public static void main(String[] args) {
        //多态可以提高代码的扩展性
        //之前的写法 继承版
        Cat c = new Cat() ;
        c.eat();
        c.sleep();
        Dog d = new Dog() ;
        d.eat();
        d.sleep();
       //现在我们可以这样写----优化代码---体现提高代码的扩展性
        提供一个静态方法,参数类型就是猫类型或者狗类型
        AnimalTool.useAnimal(new Cat());//匿名对象
        AnimalTool.useAnimal(c);//具体对象c;
        AnimalTool.useAnimal(d);//具体对象
        AnimalTool.useAnimal(new Dog()); //匿名对象
    }
}

//优化:
//定义一个类:动物工具类AnimalTool
 //使用多态的第三个前提条件:父类引用指向子类对象
class AnimalTool{
        //将构造方法私有化,目的外界类不能new
        private AnimalTool(){}
                                //父类引用指向子类对象
public static void useAnimal(Animal a){//实际参数: Animal a = new Dog();
                                               // Animal a = new Cat() ;
                                               // Animal a = new Pig() ;
        a.eat();    //编译看左,运行看右,方法重写了
        a.sleep();
    }
}

4.多态的弊端是什么?

父类引用指向子类对象
​ 对象名.方法名(); -------看父类中是否有这个方法,编译看左!
不能访问子类的特有功能

如何解决?
方式1: 创建具体的子类对象
​ 子类new子类对象
​ 在堆内存中new,消耗内存空间,不建议(从内存看角度考虑),但是你非得使用,当前是可以访问的!

方式2:

​ 将父类的引用强转转换为子类的引用 : 强制类型转换的格式
​ Zi z = (Zi) f ;
子类型 变量名 = (子类型)父的引用 ;

向下转型

//父类
class Father{
    public void teach(){
        System.out.println("教书育人!");
    }
}
//子类
class Son extends Father{
    public void teach(){
        System.out.println("教徒弟怎么上分");
    }

    //特有功能
    public void playGame(){
        System.out.println("会玩lol");
    }
}
//测试类
public class DuoTaiDemo3 {
    public static void main(String[] args) {
       //多态去测试
       //父类引用指向子类对象
       Father father = new Son() ;//多态
       father.teach() ;//编译看左,运行看右,存在 重写
       // father.playGame() ;//playGame()子类的特有功能
       System.out.println("-------------------------------------") ;
       //方式1
        Son son = new Son()  ;//不太好:在堆内存中new,消耗内存空间
        son.playGame();
        System.out.println("----------------------------------------");
      
        
       //向下转型:前提:必须存在向上转型,它不需要重写去new
        Son s = (Son) father;
        s.playGame();

5.向下转型的常见问题

向下转型使用不当,会出现运行时期异常!
ClassCastException:类转换异常:

解决方案:

  • 改动代码—因为考虑内存中和当前接收的引用类型不匹配!
class Animal{
    public void eat(){
        System.out.println("吃");
    }
    public void sleep(){
        System.out.println("睡");
    }
}

class Dog extends  Animal{
    @Override
    public void eat() {
        System.out.println("吃骨头");
    }

    @Override
    public void sleep() {
        System.out.println("狗趴着睡");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃老鼠");
    }

    @Override
    public void sleep() {
        System.out.println("狗躺着睡");
    }
}

//测试类
public class DuoTaiDemo4 {
    public static void main(String[] args) {

        //向上转型:
        Animal a = new Cat () ;//内存是猫对象  (猫是动物)
        a.eat();//编译看左,运行看右,存在重写
        a.sleep();
        //还原成猫类型Cat :向下转型--不需要重新new ,节省内存空间
        Cat c  = (Cat) a;  //猫是猫
        c.eat();
        c.sleep();
     System.out.println("-----------------------------------") ;
     a = new Dog() ;//父类的引用重写开辟空间,new的是狗,堆内存是狗对象 (狗都是动物)
     Dog d = (Dog) a; //还原成狗了        (狗是狗)

    Cat cc = (Cat)a;//语法没问题,符号强制类型转换的语法     (狗是猫:不行!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cipher_Xing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值