java基础9-面向对象进阶

1.static静态变量     

  • 被static修饰的成员变量,叫做静态变量

      特点:被该类所有对象共享;不属于对象属于类;随着类的加载而加载的,优先于对象存在

      调用方式:类名调用、对象名调用

  • 被static修饰的成员方法,叫做静态方法

      特点:多用在测试类和工具中; javabean类中很少会用

      调用方式:类名调用;对象名调用

 static的注意事项:

静态方法只能访问静态变量和静态方法

非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法

静态方法中是没有this关键字

 

javabean类:用来描述一类事务的类。比如,Student,Teacher,Dog,Cat等。

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

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

 

main方法:

public:被JVM调用,访问权限足够大;

static:被JVM调用,不用创建对象,直接类名访问;因为main方法是静态的,所以测试类中其他方法也需要是静态的

void:被JVM调用,不需要给JVM返回值

main:一个通用的名称,虽然不是关键字,但是被JVM识别

 

2.工具类

  • 类名见名知意
  • 私有化构造方法
  • 方法定义为静态

按照以下要求编写一个数组的工具类:ArrayUtil

  • 提供一个工具类方法printArr,用于返回整数数组的内容。

    返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一堆数组)

  • 提供这样一个工具方法getArrage,用于返回平均分(只考虑浮点型数组,且只考虑一堆数组)
  • 定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。

示例代码:

public class TestDemo {
    public static void main(String args[]){
        int[] arr1={1,2,3,4,5};
        String str=ArrayUtil.printArr(arr1);
        System.out.println(str);

        double arr[]={2.2,3.4,2.5,6.7};
        double avg=ArrayUtil.getAverage(arr);
        System.out.println(avg);
    }
}

public class ArrayUtil {
    private ArrayUtil() {}

    public static String printArr(int arr[]){
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for(int i = 0; i < arr.length ; i++){
            if(i==arr.length-1)sb.append(arr[i]);
            else sb.append(arr[i]+", ");
        }
        sb.append("]");
        return sb.toString();
    }

    public static double getAverage(double[] arr){
        double sum=0;
        for(int i = 0; i<arr.length; i++){
            sum+=arr[i];
        }
        return sum/arr.length;
    }
}

 

3.封装   使用关键字extends

public class Student extends Person{}

//Student称为子类(派生类),Person称为父类(基类或超类)

使用继承可以把多个子类中重复的代码抽取到父类中,提高代码的复用性。

子类可以在父类的基础上,增加其他功能,使子类更强大。

 

特点:Java只支持单继承,不支持多继承,但支持多层继承

单继承:一个子类只能继承一个父类

不支持多继承:子类不能同时继承多个父类

多层继承:子类A继承父类B,父类B可以继承父类C

每一个类都直接或间接的继承于Object

 

  • 构造方法:父类的构造方法不能被子类继承
public class TestDemo {
    public static void main(String args[]) {
        Zi z1 = new Zi();//不报错因为类中会自动添加空参构造方法
        Zi z2 = new Zi("zhangsan",23);//会报错
    }
}
    class Fu{
        String name;
        int age;

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

    class Zi extends Fu{
    }

子类中所有的构造方法默认先访问父类中的无参构造,再执行自己

子类构造方法的第一行语句默认是:super(),不写也存在

  • 成员变量:子类能够继承父类的成员变量,但是父类中被private修饰的不能直接使用,需要通过get和set方法使用

    访问特点:就近原则,谁离我近我就用谁//先局部再本类,然后父类,逐级向上

System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);

 

  • 成员方法:只有父类中的虚方法才能被子类继承

    (从最顶级的父类开始设计虚方法表,二级父类在顶级的基础上加上自己的虚方法表,在继承关系中顺延)虚方法:非private,非static,非final

    访问特点:直接调用满足谁离我近我就用谁;super调用直接访问父类

 

4.方法的重写(注解@Override):当父类的方法不能满足子类现在的需求时,需要进行方法重写

    书写格式:在继承体系中,子类出现和父类一模一样的方法声明,我们就称子类这个方法是重写的方法。方法的重写会覆盖虚方法表中的方法

 

重写注意事项和要求:

  • 重写方法的名称、形参列表必须与父类中的一致。
  • 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protectes<public)
  • 子类重写父类方法时,返回值类型子类必须小于等于父类
  • 建议:重写的方法尽量和父类保持一致
  • 只有被添加到虚方法表中的方法才能被重写

5.多态  同类型的对象,表现出的不同形态

表现形式:    父类类型 对象名称 = 子类对象;

多态的前提:有继承关系;有父类引用指向子类对象(例如Fu f = new Zi(); );有方法重写

调用成员方法:编译看左边,运行看右边(javac编译代码的时候,会看左边的父类中有没有这个方法,如果有编译成功,反之编译失败。java运行代码的时候,实际上运行的是子类中的方法。)

调用成员变量:编译看左边,运行也看左边

 

多态的优势

(1) 在多态形势下,右边对象可以实现解耦合,便于扩展和维护。

Person p = new Student();//当需要时可以改成Teacher();
p.work;//业务逻辑发生改变时,后续代码无需修改

(2)定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。

弊端:

public class TestStudent {
    public static void main(String[] args){
        Animal a = new Dog();
        a.eat();//编译看左边,运行靠右边

        //多态的弊端:不能调用子类的特有功能
        //报错原因:调用成员方法时编译看左边,运行看右边
        //编译的时候检查左边的父类中是否有该方法,没有则直接报错
        a.lookHome();//报错
     //解决方案 变回子类型
     //Dog d = (Dog)a;
//d.lookHome();
} } class Animal{ public void eat(){ System.out.println("动物在吃东西"); } } class Dog extends Animal{ @Override public void eat(){ System.out.println("狗吃骨头"); } public void lookHome(){ System.out.println("狗看家"); } } class Cat extends Animal{ @Override public void eat(){ System.out.println("猫吃鱼"); } }

a instancdof Dog: a是不是Dog类型

新特性为 a instancdof Dog d: 先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d; 如果不是,则不强转,结果直接是false

 

引用数据类型的类型转换,有几种方式? 自动类型转换,强制类型转换

强制类型转换能解决什么问题?

  • 可以转换成真正的子类类型,从而调用子类独有功能。
  • 转换类型与真实对象类型不一致会报错。
  • 转换的时候用instanceof关键字进行判断

 6.包和final

包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。

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

package com.cnblogs.domain.Student;//全类名、全限定名

使用其他类的规则:

使用同一个包中的类时,不需要导包。

使用java.lang包中的类时,不需要导包。

其他情况都需要导包。

如果同时使用两个包中的同名类,需要用全类名(包名+类名)。

 

  • final 是最终的,不可以被改变的。

    用final修饰一个方法:表明该方法是最终方法,不能被重写;用final修饰一个类:表明该类是最终类,不能被继承;用final修饰一个变量:叫做常量,只能被赋值一次。

 

  • 常量 命名规范:单个单词全部大写;多个单词:全部大写,单词之间用下划线隔开

    注:final修饰的基本变量是基本类型,那么变量存储的数据值不能发生改变; final修饰的变量是引用类型,那么变量存储的地址值不能发生改变,对象内部的可以改变。

 

  • 权限修饰符: 是用来控制一个成员能够被访问的范围的, 可以修饰成员变量,方法,构造方法,内部类。

    四种作用范围由小到大:private < 空着不写(default)< protected < public

    image

 权限修饰符的使用规则:实际开发中一般只用private和public,成员变量私有,方法公开

    特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有

 

  • 构造代码块:写在成员位置的代码块

      作用:可以把多个构造方法中重复的代码抽取出来

      执行时机:我们在创造本类对象的时候会先执行构造代码块再执行构造方法

  • 静态代码块:   格式:static{}

    特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次

    使用场景:在类加载的时候,做一些数据初始化的时候使用

static{
        System.out.println("静态代码块执行");//只执行一次
}    

 

7.抽象类和抽象方法:    抽象方法子类必须强制重写

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

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

定义示例:

public abstract class Person {//抽象类
    public abstract void work();//抽象方法
}

注意事项:

(1) 抽象类不能实例化(不能创建对象)

(2) 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

(3) 可以有构造方法

(4) 抽象类的子类要么重写抽象类中的所有抽象方法;要么是抽象类

public abstract class Animal {
    private String name;
    private int age;

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

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void drink(){
        System.out.println("动物在喝水");
    }
    public abstract void eat();
}
public class Frog extends Animal{

    public Frog() {
    }

    public Frog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }
}

 

8.接口  接口是一种规则,是对行为的抽象

  • 接口用关键字interface来定义   public Interface 接口名{}
  • 接口不能实例化
  • 接口和类之间是实现关系,通过implements关键字表示  public class 类名 implements 接口名{}
  • 接口的子类(实现类):要么重写接口中的所由抽象方法,要么是抽象类
  • 实现一个接口要重写里面所有的抽象方法

注意1:接口和类的实现关系,可以单实现,也可以多实现。

    public class 类名 implements 接口名1,接口名2{}

注意2:实现类还可以在继承一个类的同时实现多个接口。

    public class类名extends父类 implements接口名1,接口名2{}

public class Java01 {
    public static void main(String[] args) {
        Frog f= new Frog("小青", 1);
        System.out.println(f.getName()+", "+f.getAge());
        f.eat();
        f.swim();

        Rabbit r =  new Rabbit("小白",2);
        System.out.println(r.getName()+", "+r.getAge());
        r.eat();
    }
}
ublic abstract class Animal {
    private String name;
    private int age;

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

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void drink(){
        System.out.println("动物在喝水");
    }
    public abstract void eat();
}
public interface Swim {
    public abstract void swim();
}
public class Rabbit extends Animal{
    public Rabbit() {
    }

    public Rabbit(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("兔子吃胡萝卜");
    }
}
public class Frog extends Animal implements Swim{

    public Frog() {
    }

    public Frog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }

    @Override
    public void swim() {
        System.out.println("青蛙在游泳");
    }
}
public class Dog extends Animal implements Swim{
    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

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

    @Override
    public void swim() {
        System.out.println("狗在游泳");
    }
}

接口中成员的特点:

  • 成员变量 只能是常量 默认修饰符:public static final 
  • 无构造方法
  • 成员方法 只能是抽象方法 默认修饰符 public abstract

 

接口和类之间的关系:

  • 类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承
  • 类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
  • 接口和接口的关系:继承关系,可以单继承,也可以多继承

JDK8后接口新增方法:

(1) 允许在接口中定义默认方法,需要使用关键字default修饰(作用:解决接口升级的问题)

默认方法定义格式:public default 返回值类型 方法名(参数列表){}

范例:public default void show (){}

  注意事项:

  • 默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字。 
  • public可以省略,default不能省略
  • 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。

 (2) 允许在接口中定义静态方法,需要用static修饰。

静态方法的定义格式:public static 返回值类型 方法名(参数列表){}

范例:public static void show(){}

  注意事项:

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  • public可以省略,static不能省略

JDK9后接口新增方法:

(3) 接口中私有方法的定义格式:

格式1:private 返回值类型 方法名(参数列表){} //为默认方法服务(普通的私有方法)

范例1:private void show(){}

格式2:private static 返回值类型 方法名(参数列表){} //为静态方法服(静态的私有方法)

范例2:private static void method(){}

 

接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。

当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。

 

适配器:解决接口与接口实现类之间的矛盾问题

当一个接口中抽象方法过多,但是只需要使用其中一部分的时候就可以适配器设计模式

书写步骤:(1) 编写中间类XXXAdapter实现对应的接口,对接口中的抽象方法进行空实现

(2) 让真正的实现类继承中间类,重写需要用的方法

(3) 避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰

public interface Inter {
    public abstract void method1();
    public abstract void method2();
    public abstract void method3();
    public abstract void method4();
    public abstract void method5();
}
public class InterImpl extends InterAdapter{
    //需要哪个方法就重写哪个方法
    @Override
    public void method5() {
        System.out.println("只要用第五个方法");
    }
}
public abstract class InterAdapter implements Inter{//定义为空方法
    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }

    @Override
    public void method4() {

    }

    @Override
    public void method5() {

    }
}

9.内部类:成员内部类/ 静态内部类/ 局部内部类/ 匿名内部类

在一个类的里面再定义一个类,里面的类叫内部类

内部类表示的事务是外部类的一部分;内部类单独出现没有任何意义

内部类的访问特点:

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象
//写一个javabean类描述汽车
//属性:汽车品牌、汽车年龄、汽车颜色、发动机品牌、使用年限
public class Car {//外部类
    String carName;
    int carAge;
    int carColor;
    class Engine{//内部类(成员内部类)
        String engineName;
        int engineAge;
    }
}

 

成员内部类

获取成员内部类的对象:(1) 在外部类中编写方法,对外提供内部类对象

(2)直接创建格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象;

示例1:

//方法一
public class Outer{
    String name;
   
    class Inner{

    }  
}


public class Test{
    public static void main(String args[]) {
        Outer.Inner oi = new Outer().new Inner();
    }
}

//方法二
public class Outer{
    String name;
   
    private class Inner{

    }  
    public Inner getInstance(){
         return new Inner();
    }
}


public class Test{
    public static void main(String args[]) {
        Outer o = new Outer();
        o,getInstance();
    }
}

示例2:

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

public class TestDemo {
    public static void main(String args[]) {
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
    }
}

 

静态内部类(也是成员内部类中的一种)

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

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

调用非静态方法的格式:先创建对象,用对象调用。

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

public class TestDemo {
    public static void main(String args[]) {
        //创建静态内部类的对象 只要是静态的东西,都可以用类名点直接获取
        Outer.Inner oi = new Outer.Inner();
        oi.show();

        //静态方法
        Outer.Inner.show2();
    }
}

public class Outer {
     int a = 10;
     static int b = 20;
     static class Inner {
        public void show() {
           Outer o =new Outer();
           System.out.println(o.a);
           System.out.println(b);
        }
         public static void show2() {
             System.out.println("show2");
         }
    }
}

局部内部类

  • 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
  • 外界无法直接使用,需要在方法内部创建对象并使用。
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
public class TestDemo {
    public static void main(String args[]) {
        Outer o = new Outer();
        o.show();
    }
}
public class Outer {
    int b = 20;
    public void show(){
       int a = 10;
        class Inner{//局部内部类
            String name;
            int age;

          public void method1(){
              System.out.println(a);
              System.out.println(b);
              System.out.println("method1");
          }
          public static void method2(){
              System.out.println("method2");
          }
        }
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();
    }
}

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

格式:

    new 类名或者接口名(){

      重写方法;//包含了继承或实现;方法重写;创建对象(整体就是一个类的子类对象或者接口的实现类对象)

    }

使用场景:当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象。如果实现类只要使用一次,就可以通过匿名内部类简化代码

public class TestDemo {
    public static void main(String args[]) {
        new Swim(){  //没有名字的类是大括号部分 括号中是对Swim接口的实现 new创建该类的对象
            @Override
            public void swim() {
                System.out.println("重写了游泳的方法");
            }
        };
        method(
                new Animal(){  //没有名字的类是大括号部分 括号中是animal的子类 new创建该类的对象
                    @Override
                    public void eat() {
                        System.out.println("重写了eat的方法");
                    }
                }
        );
    }
    public static void method(Animal a){//Animal a = 子类对象 多态
        a.eat();//编译看左边,运行看右边
    }
}

 

posted @ 2025-10-20 23:58  chen1chen  阅读(8)  评论(0)    收藏  举报