文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
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;//语法没问题,符号强制类型转换的语法 (狗是猫:不行!)