Java学习笔记(二)

本文深入讲解Java中的继承特性,包括静态变量、静态方法和main方法的理解,以及如何创建工具类。接着探讨多态的概念、表现形式及其在实际编程中的应用。此外,详细阐述了内部类的种类、访问特点和匿名内部类的使用场景,帮助读者巩固Java基础知识。
摘要由CSDN通过智能技术生成

Java学习笔记(二)

文章目录

1 static

static表示静态,是Java里面的一个修饰符,可以修饰成员变量,也可以修饰成员方法。

1.1 静态变量

  • 被static修饰的成员变量叫做静态变量
    • 特点:被该类所有对象共享
    • 调用方式:类名调用或对象名调用
    • 不属于对象,属于类
1.1.1 static内存图

image-20221030200214190

注意:静态变量是随着类的加载而加载的,优先于对象出现

teacherName的初始化值为null,后被覆盖为"***"

image-20221030200722093

image-20221030200853915

1.2 静态方法

  • 被static修饰的成员方法叫做静态方法
    • 多用于测试类和工具类
    • JavaBean类很少会用
    • 类名调用或对象名调用

总结:

JavaBean类:用来描述一类事物的类

测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的主入口

工具类:不是用来描述一类事物,而是帮我们做一些事情的类

工具类的特点:

  • 见名知意
  • 私有化构造方法(即不能创建对象,因为没有意义)
  • 方法定义为静态(可直接调用)

创建工具类:

package Code;

public class MathUtil {

    //私有化构造方法
    private MathUtil(){

    }

    //静态方法
    public static int sum(int[] arr){
        int sum=0;
        for (int i = 0; i < arr.length; i++) {
            sum=sum+arr[i];
        }
        return sum;
    }
}

测试类:

package Code;

public class test51 {
    public static void main(String[] args) {
        int[] arr={1,2,3,4};
        System.out.println(MathUtil.sum(arr));
    }
}
1.2.1 练习:创建学生工具类

学生类:

package test2;

public class Student {
    private String name;
    private int age;
    private String gender;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

工具类:

package test2;

import java.util.ArrayList;

public class StudentUtil {
    private StudentUtil(){

    }
    public static int getMaxAge(ArrayList<Student> list){
        int max=list.get(0).getAge();
        for(Student i:list){
            int age=i.getAge();
            if(age>max){
                max=age;
            }
        }
        return max;
    }
}

测试类:

package test2;

import java.util.ArrayList;

public class test {
    public static void main(String[] args) {
        ArrayList<Student> list=new ArrayList<>();
        Student s1=new Student("cjm",22,"男");
        Student s2=new Student("sqd",19,"女");
        Student s3=new Student("cjm他爹",36,"女");
        list.add(s1);
        list.add(s2);
        list.add(s3);
        System.out.println(StudentUtil.getMaxAge(list));
    }
}
1.2.2 总结
  • 非静态方法可以访问所有

  • 静态方法中没有this关键字(静态方法是共享的,无法指定对象)

  • 静态方法只能访问静态变量或静态方法

    • 非静态变量和非静态方法和对象有关
package test3;

public class CJM {
    static String name="cjm";
    private int age;

    public CJM() {
    }

    //this表示当前方法调用者(对象)的地址值
    //this由虚拟机赋值
    //原来的写法:public void print1(){}
    public void print1(CJM this){
        System.out.println("cjm是大傻逼!");

        //调用其他方法时:
        //原来的写法:print2();
        //实质:
        this.print2();  //this——不用写
    }


    public void print2(CJM this){
        System.out.println("cjm是大聪明!");
    }

    public static void print3(){
        System.out.println("明猪");
    }
    
}
1.2.3 重新认识main方法

image-20221030213558284

package test3;

public class test {
    public static void main(String[] args) {
        
        //用Edit Configuration给字符串数组args传入数据cjm pig CJM PIG
        
        System.out.println(args.length);  //4
        
        for (int i = 0; i < args.length; i++) {
            System.out.print(args[i]+" ");  //cjm pig CJM PIG
        }
        
    }
}

2 继承

2.1 引入

假如我们要定义如下类:
学生类,老师类和工人类,分析如下。

  1. 学生类
    属性:姓名,年龄
    行为:吃饭,睡觉

  2. 老师类
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,教书

  3. 班主任
    属性:姓名,年龄,薪水
    行为:吃饭,睡觉,管理

如果我们定义了这三个类去开发一个系统,那么这三个类中就存在大量重复的信息(属性:姓名,年龄。行为:吃饭,睡觉)。这样就导致了相同代码大量重复。

解决方法:

假如多个类中存在相同属性和行为时,我们可以将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。

其中,多个类可以称为子类,单独被继承的那一个类称为父类超类(superclass)或者基类

2.2 继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

public class Student extends Person{}

Student称为子类,Person称为父类。

2.3 继承的应用场景

当类与类之间,存在相同的内容,并满足子类是父类中的一种,就可以考虑用继承来优化代码。

2.4 继承的特点

  • 只能单继承,一个子类只能有一个直接父类
  • Java不支持多继承,但支持多层继承
  • Java中所有的类都直接或间接继承于Object类

子类只能访问父类中的非私有成员。

2.5 子类能继承父类中的哪些内容

父类中的内容内容权限能否继承内容权限能否继承
构造方法非私有0private0
成员变量非私有1private1
成员方法非私有1private0
  • 父类的构造方法不能被子类继承

在这里插入图片描述

  • 父类的成员变量能被子类继承

image-20221101213246262

  • 父类的非私有成员方法能被子类继承

成员方法能被添加到虚方法表,就能被子类继承

Java中所有的类都直接或间接继承于Object类,Object类虚方法表长度为5,有5个虚方法

image-20221101230334958

image-20221101230204346

2.6 继承中各成员的访问特点

2.6.1 成员变量的访问特点
  • 就近原则

    • 先在局部位置(方法内部)找,本类成员量找,父类成员变量找,逐级往上
  • 如果子类和父类变量出现重名

System.out.print(name);
System.out.print(this.name);
System.out.print(super.name);
2.6.2 成员方法的访问特点
  • 就近原则
    • 先在本类中查看被调用的方法,如果没有,就会调用从父类中继承下来的方法
super.method();  //直接调用父类的方法
2.6.2.1 方法重写

image-20221101233342210

2.6.2.2 方法重写的本质

image-20221101233614587

2.6.2.3 方法重写的注意事项和要求

image-20221101233913471

2.6.3 构造方法的访问特点

image-20221102001346100

2.7 this和super总结

image-20221102002857142

2.8 练习

image-20221102003601429

3 多态 包 final

3.1 多态

3.1.1 什么是多态

对象的多种形态

3.1.2 多态表现形式
父类名称 对象名称=子类名称
3.1.3 多态调用成员的特点
Animal a=new Dog();
  • 调用成员变量:编译看左边,运行也看左边

    • 编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个成员变量,如果有,编译成功,如果没有,编译失败
    • 运行看左边:Java运行代码的时候,实际上运行的是父类的成员变量
  • 调用成员方法:编译看左边,运行也看右边

    • 编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个成员方法,如果有,编译成功,如果没有,编译失败

    • 运行看左边:Java运行代码的时候,实际上运行的是子类的成员方法

实质:

成员变量:在子类的对象中,会把父类的成员变量也继承下来

成员方法:如果子类对方法进行了重写,那么子类的虚方法表会把父类的原有方法覆盖

image-20221107160124047

3.1.4 多态的前提
  • 有继承关系
  • 有父类引用指向子类对象
  • 有方法重写
3.1.5 多态的好处

使用父类进行参数传递,可以接收所有类型子类对象,体现多态的拓展性

3.1.6 多态的弊端

不能使用子类中的特有功能(方法)

解决方法:强制类型转换,将对象转换成子类类型,从而调用子类的特有功能

注意:

  • 转换类型与真实对象类型不一致会报错
  • 多个子类对象时,用instanceof关键字进行判断
Dog d=(Dog)a;

判断语句:

if(a instanceof Dog){
    Dog d=(Dog)a;
}

JDK14以后的写法:

if(a instanceof Dog d){
}

3.2 包

3.2.1 什么是包

包就是文件夹,用来管理不同功能的Java类

3.2.2 包名规则

公司域名反写+包的作用,需要全部英文小写,见名知意

3.2.3 使用其他类的规则
  • 使用同一个包中的类时,不需要导包
  • 使用java.lang包中的类时,不需要导包
  • 其他情况都需要导包
  • 如果同时使用两个包中的同名类,需要用全类名(包名+类名)

3.3 final

  • final修饰方法:表明该方法是最终方法,不能被重写
  • final修饰类:表面该类是最终类,不能被继承
  • final修饰的变量叫做常量,只能被赋值一次
3.3.1 常量的命名规范
  • 单个单词:全部大写
  • 多个单词:全部大写,单词之间用下划线"_"隔开

注意:

  • final修饰的是基本数据类型,变量存储的数据值不可变

  • final修饰的是引用数据类型,变量存储的地址值不可变,对象内部可变

4 权限修饰符和代码块

4.1 权限修饰符

4.1.1 作用范围

四种作用范围由小到大:private< 缺省/默认 < protected < public

修饰符同一个类中同一个包中其他类不同包下的子类不同包下的无关类
private×××
缺省/默认××
protected×
public
4.1.2 使用规则

实际开发中,一般只用private和public

  • 成员变量私有
  • 成员方法公开
    • 如果该方法是抽取其他方法的共性代码,这个方法一般私有

4.2 代码块

4.2.1 局部代码块

提前结束变量的生命周期

package Code;

public class test51 {
    public static void main(String[] args) {
        {
            int a=50;
        }  
        //局部代码块
        //当程序运行到这里,a会从内存中消失
        System.out.println(a);  //报错
    }
}
4.2.2 构造代码块(不够灵活,逐渐淘汰)
  • 写在成员位置的代码块
  • 作用:可以把多个构造方法中重复的代码抽取出来
  • 创建对象时会优先执行构造代码块再执行构造方法(每一次创建对象都会执行)
package Code;

public class test52 {
    private String name;
    private int age;

    //构造代码块
    {
        System.out.println("开始创建对象");
    }

    public test52() {
        //System.out.println("开始创建对象");
    }

    public test52(String name, int age) {
        //System.out.println("开始创建对象");
        this.name = name;
        this.age = age;
    }
}

解决办法:

4.2.3 静态代码块
static{}

特点:随着类的加载而加载,并且只执行一次

作用:可以实现方法的数据初始化,避免该方法被重复调用时的多次数据初始化

5 抽象类 接口 内部类

5.1 抽象类

5.1.1 抽象方法

将共性的行为(方法)抽取到父类后,由于每个子类执行的内容不一样,所以父类不能确定具体的方法体。该方法就

可以定义为抽象方法。

public abstract void work();
//强制子类必须按照这种格式重写
5.1.2 抽象类

如果一个类中存在抽象方法,该类必须声明为抽象类。

public abstract class Studnt{
    
}
5.1.3 注意事项
  • 抽象类不能实例化(不能创建对象)
  • 抽象类不一定有抽象方法,但是有抽象方法一定是抽象类
  • 可以有构造方法
  • 抽象类的子类:
    • 要么重写抽象类中所有抽象方法
    • 要么是抽象类

5.2 接口

5.2.1 接口的定义和使用

在这里插入图片描述

5.2.2 接口中成员的特点

注意:JDK7以前,接口中只能定义抽象方法

  • 成员变量:只能是常量,**默认修饰符public static final **
  • 无构造方法
  • 成员方法:只能是抽象方法,默认修饰符public abstract
public interface Inter {
    int a=10;    //默认修饰符public static final
    void work();    //默认修饰符public abstract
}
5.2.3 接口与类之间的关系

在这里插入图片描述

5.2.4 JDK8以后接口中的新增方法
5.2.4.1 默认方法
  • 允许在接口中定义默认方法,用default关键字修饰
  • 作用:解决接口升级问题

接口中默认方法定义格式:

public default void show(){
    
}

接口中默认方法的注意事项:

  • 默认方法不是抽象方法,不强制要求被重写,如果被重写,要去掉default关键字
  • public可以省略,default不可以省略
  • 如果实现多个接口,多个接口中存在相同名字的默认方法,子类必须对该默认方法进行重写
5.2.4.2 静态方法
  • 允许在接口中定义静态方法,用static关键字修饰

接口中静态方法定义格式:

public static void show(){
    
}

接口中静态方法的注意事项:

  • 静态方法只能通过接口名调用,不能通过类名或对象名调用
  • public可以省略,static不可以省略
5.2.4.3 JDK9以后新增的私有方法

作用:抽取接口中的重复代码,并在接口中进行调用,并且不被外界访问

  • 普通的私有方法,为默认方法服务
  • 静态的私有方法,为静态方法服务

接口中私有方法定义格式:

private void show1(){
    
}

private static void show2(){
    
}
5.2.5 接口总结
  • 接口代表规则,是行为的抽象,想要一个类拥有一个行为,就让这个类实现对应接口
  • 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称为接口多态
5.2.6 适配器设计模式

当一个接口中抽象方法太多,而实现类只需要其中一部分抽象方法,这时候就可以使用适配器设计模式。

书写步骤:

  • 创建中间类XXXAdapter,实现对应接口
  • 对接口中所有抽象方法进行空实现
  • 让真正的实现类继承中间类,并重写需要用的方法
  • 为了避免其他类创建适配器类的对象,将中间的适配器类用abstract关键字修饰
5.2.6 综合案例

image-20221108003509592

5.3 内部类

类的五个成员:属性、方法、构造方法、代码块、内部类

5.3.1 什么是内部类

在一个类(外部类)的内部再创建一个类,这个类就称为内部类。

  • 内部类表示的事物是外部类的一部分
  • 内部类单独出现没有任何意义
5.3.2 内部类的访问特点
  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象
5.3.3 内部类的分类
  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类
5.3.3.1 成员内部类
  • 写在成员位置的,属于外部类的成员

  • 成员内部类可以被一些修饰符修饰,比如:private、默认、protected、public

    • private修饰:只能在外部类里面使用,外界不可用
    • 默认权限:只能在本包使用,其他包用不了
    • protected修饰:本包的其他类使用,包括其他包的子类
    • public修饰:表示所有地方都可以创建成员内部类的对象
  • 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才能定义静态变量

5.3.3.2 获取成员内部类的对象
  • 在外部类中编写方法,对外提供内部类的对象(private)
public class Out {
    String name;

    private class In{

    }

    public In getIn(){
        return new In();
    }
    
}
public class test {
    public static void main(String[] args) {

        Out o=new Out();
        Object oi=o.getIn();  //获取内部类对象

    }
}
  • 直接创建格式:

外部类名.内部类名 对象名=外部类对象.内部类对象;

public class Out {
    String name;

    //内部类
    protected class In{

    }
}
public class test {
    public static void main(String[] args) {
        
        //创建内部类对象
        Out.In oi=new Out().new In();

    }
}
5.3.3.3 成员内部类的变量
  • 外部类成员变量与内部类成员变量重名:Out.this获取外部类对象的地址值
public class Out {
    int a=30;

    public class In{
        int a=20;
        public void show(){
            int a=10;
            System.out.println(a);  //10
            System.out.println(this.a);  //20
            System.out.println(Out.this.a);  //30
        }
    }

}
public class test {
    public static void main(String[] args) {

        Out.In oi=new Out().new In();
        oi.show();
        
        //或者
        
        Out o=new Out();
        o.getIn().show();

    }
}

image-20221112144458785

5.3.3.4 静态内部类

静态内部类只能调用外部类的静态变量和静态方法,如果在静态内部类想要访问外部类的非静态成员,需要创建外

部类对象。

5.3.3.5 创建静态内部类对象的格式

外部类名.内部类名 对象名=new 外部类名.内部类名();

  • 调用静态内部类非静态方法:先创建静态内部类对象,再用对象调用

  • 调用静态内部类静态方法:外部类名.内部类名.方法名();

public class Out {
    int a=10;
    static int b=20;

    public static class In{
        public void show1(){
            //调用外部类静态成员变量
            System.out.println(b);

            //调用外部类非静态成员变量
            Out o=new Out();
            System.out.println(o.a);
        }
        public static void show2(){
            //调用外部类静态成员变量
            System.out.println(b);

            //调用外部类非静态成员变量
            Out o=new Out();
            System.out.println(o.a);
        }
    }
}
public class test {
    public static void main(String[] args) {

        //调用静态内部类静态方法
        Out.In.show2();  //20 10

        //调用静态内部类非静态方法
        Out.In oi=new Out.In();
        oi.show1();  //20 10
    }
}
5.3.3.6 局部内部类
  • 将内部类定义在方法里面就叫局部内部类,类似方法里面的局部变量,不能用public、static、protected修饰
    • 只能用final修饰
  • 局部内部类不能被外界访问,只能在方法内创建局部内部类对象并使用
  • 局部内部类可以直接访问外部类的成员,也可访问方法内的局部变量
public class Out {
    int age=19;
    
    public void show(){
        int height=180;
        
        class In{
            public void method1(){
                System.out.println("method1");
            }
            public static void method2(){
                System.out.println("method2");
            }
        }
        
        In.method2();
        In i=new In();
        i.method1();
    }
    
}
public class test {
    public static void main(String[] args) {
        Out o=new Out();
        o.show();
    }
}
5.3.4 匿名内部类(重点)

隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。

整体是一个类的子类对象或接口的实现类对象

new 接口名/类名(){
    重写方法
};
5.3.4.1 实现接口
public interface Swim {
    public abstract void swim();
}
public class test {
    public static void main(String[] args) {
        
        new Swim(){
            @Override
            public void swim(){
                System.out.println("重写抽象方法");
            }
        };
        //实现Swim接口
        //方法重写
        //new创建没有名字的对象
        //()表示创建方法为空参构造
    }
}
5.3.4.2 继承类
public abstract class Animal {
    public abstract void eat();
}
public class test {
    public static void main(String[] args) {

        new Animal(){
            @Override
            public void eat(){
                System.out.println("重写抽象类里面的抽象方法");
            }
        };
        
        //继承Anima父类
        //方法重写
        //new创建没有名字的子类对象
        //()表示创建方法为空参构造
    }
}
5.3.4.3 应用场景

当方法的参数是接口或类时:

子类或实现类只需要用一次,就不用那么麻烦再创建子类或实现类,直接将匿名内部类作为参数传递给方法。

public class test {
    public static void main(String[] args) {

        method(
                new Animal(){
                    @Override
                    public void eat(){
                        System.out.println("狗吃骨头");
                    }
                }
        );
    }

    public static void method(Animal a){  //Animal a=子类对象 多态
        a.eat(); //编译看左边,运行看右边
    }
}
5.3.4.4 补充
public class test {
    public static void main(String[] args) {

        //多态
        Animal a=new Animal(){
            @Override
            public void eat(){
                System.out.println("狗吃骨头");
            }
        };

        //接口多态
        Swim s=new Swim() {
            @Override
            public void swim() {
                System.out.println("狗刨");
            }
        };

        new Swim() {
            @Override
            public void swim() {
                System.out.println("狗刨");
            }
        }.swim();  //狗刨
        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值