9.java面向对象进阶

1.static关键字

static是静态的意思,可以修饰成员变量,表示该变量只在内存中只存储一份,可以被共享访问、修改
成员变量可以分为2类
1.静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数信息等需要被共享的信息,可以被共享访问
2.实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息

public class User {
// 静态成员变量:由static修饰,属于类,加载一次,可以被共享访问
    public static int onLineNumber;
// 实例成员变量,无static修饰,属于每个对象
    private String name;
    private int age;

    public static void main(String[] args) {

        User.onLineNumber ++;
//        同一个类中访问静态成员变量,类名可以省略不写
        System.out.println(onLineNumber);

        User u1 = new User();
        u1.name = "张三";
        u1.age = 32;
        System.out.println(u1.name);
        System.out.println(u1.age);
        // 对象.静态成员变量(不推荐)
        System.out.println(u1.onLineNumber);
    }
}

成员方法的分类
静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问
实例成员方法(无static修饰,属于对象),只能用对象触发访问

表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法
如果该方法是执行一个通用哦那个能为目的,或者方便访问的,则可以申明成静态成员方法

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

    public void study() {
        System.out.println(name+"在学习");
    }
    // 静态方法 可以被类和对象共享访问
    public static void getMax(int a, int b) {
        System.out.println(a > b ? a : b);
    }

    public static void main(String[] args) {
        Student s1 = new Student();
        Student.getMax(10,20);

        // 同一个类中访问静态成员 可以省略类名不屑
        getMax(20,40);

        // 实例方法
        s1.name = "张三";
        s1.study();
    }
}

2.static实际应用案例:使用静态方法定义工具类

对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类
工具类的作用:一是方便调用,二是提高了代码复用

public class VerifyTool {
    // 静态方法
    public static String createCode(int n) {
        // 1.使用String开发一个验证码
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
        // 2.定义一个变变量存储5位随机的字符作为验证码
        String code = "";
        // 3.循环
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            int index = r.nextInt(chars.length());
            code += chars.charAt(index);
        }
       return code;
    }
}
    public static void main(String[] args) {
        System.out.println("验证码"+ VerifyTool.createCode(5));
    }

工具类原理和延申
一次编写,处处可用
建议将工具类的构造器私有,不让工具类对外产生对象

private VerifyTool() {
}

封装将数组元素拼接成字符串和求平均分工具类

public class ArrayUtils {
    private ArrayUtils() {

    }

    public static String toString(int[] arr) {
        if(arr != null) {
            String result = "[";
            for (int i = 0; i < arr.length; i++) {
                result += i == arr.length -1 ? arr[i] : arr[i] + ",";
            }
            result += "]";
            return result;
        }
        return null;
    }

    public static double getAverage(int[] arr) {
        int max = arr[0];
        int min = arr[0];
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] > max) {
                max = arr[i];
            }
            if(arr[i] < min) {
                max = arr[i];
            }
            sum += arr[i];
        }
        return (sum - max - min) / (arr.length - 2);
    }
}
public static void main(String[] args) {
     int[] arr = {10,20,30};
     System.out.println(arr);
     System.out.println(ArrayUtils.getAverage(arr));
     System.out.println(ArrayUtils.toString(arr));
 }

static访问注意事项
静态方法只能访问静态的成员,不可以直接访问实例成员
实例方法可以访问静态的成员,也可以访问实例成员
静态方法中是不可以出现this关键字的

3.static应用知识:代码块

代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类),定义在类中方法外
静态代码块
格式: static {}
特点:需要通过static关键字修饰,随着类的加载而加载, 并且自动触发,只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,一遍后续使用

public class TestDemo1 {
    public static String myName;
    public static void main(String[] args) {
        System.out.println("main方法执行输入");
        System.out.println(myName);
    }
    /*
    *  与类一起加载,自动触发一次,优先执行
    * 作用 可以在程序加载时进行静态数据的初始化操作(准备内容)
    * */
    static {
        System.out.println("静态代码块触发执行");
        myName = "张三";
    }
}

构造代码块(用的比较少)
格式: {}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
使用场景:初始化实例资源

public class TestDemo2 {
    private String name;

    /*
     * 属于对象的,与对象一起加载,自动触发执行
     * */
    {
        System.out.println("构造代码快被触发执行一次");
        name = "张三";
    }
    public TestDemo2() {
        System.out.println("构造器被触发执行");
    }
    public static void main(String[] args) {
       TestDemo2 t1 = new TestDemo2();
        System.out.println(t1.name);
        TestDemo2 t2 = new TestDemo2();
        System.out.println(t2.name);
    }
}

4.静态代码块的作用

案例:斗地主游戏
在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据

public class StativCodeTest3 {
    /*
    * 模拟斗地主牌初始化操作
    * 准备一个容器,存储54张牌对象,这个容器建议使用静态的集合,静态的集合只会加载一次
    *  点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
         花色: "♠", "♥", "♣", "♦"
    * */
   static ArrayList<String> cards = new ArrayList<>();

   /*
   *  在游戏启动之前需要准备好54张牌放进去,使用静态代码块进行初始化
   * */
    static {
        // 加载54张牌
       // 准备4中花色
       String[] colors = {"♠", "♥", "♣", "♦"};
       // 定义点数
       String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
       for (int i = 0; i < sizes.length; i++) {
          for (int j=0; j<colors.length;j++) {
              cards.add(sizes[i] + colors[j]);
          }
       }
       cards.add("小王");
       cards.add("大王");
   }

    public static void main(String[] args) {
        System.out.println("新牌"+cards);
    }
}

5.static设计模式:单例模式

什么事设计模式
设计模式是一套被前人反复使用、多数人知晓、经过分类编目的代码设计经验的总结,后来者可以直接拿来解决问题
设计模式是软件设计中的常见解决方案,好的设计模式可以进一步的提高代码的重用性

单例模式:可以保证系统中,应用该模式的这个类只用只有一个实例,即一个类永远只能创建一个对象

单例的场景和作用
例如任务管理器对象只需要一个就可以解决问题了,这样可以节省内存空间

饿汉单例设计模式
在用类获取对象的时候,对象已经提前创建好了
设计步骤

定义一个类,把构造器私有
定义一个静态变量存储一个对象

public class SingleInstance1 {
    // 2.定义一个公开的静态的成员变量村粗一个类的对象
    //    饿汉:在这里加载静态变量的时候就会创建对象了
    public static SingleInstance1 instance= new SingleInstance1();
    // 1.把构造器私有
    private SingleInstance1() {

    }
}
public class Test {
    public static void main(String[] args) {
        SingleInstance1 s1 = SingleInstance1.instance;
        SingleInstance1 s2 = SingleInstance1.instance;
        SingleInstance1 s3 = SingleInstance1.instance;
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
    }
}

懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)

定义一个类,把构造器私有
定义一个静态变量存储一个对象
提供一个返回单例对象的方法

public class SingleInstance2 {
    // 2.创建一个静态的成员变量存储本类的对象,注意:不能初始化对象
    private static SingleInstance2 instance;
    // 1.私有构造器
    private SingleInstance2() {

    }
    // 3.定义一个方法,让其他地方可以调用获取一个对象
    public static SingleInstance2 getInstance() {
        if(instance == null) {
            // 第一次获取对象
            instance = new SingleInstance2();
        }
        return instance;
    }
}
public class Test2 {
    public static void main(String[] args) {
        SingleInstance2 s1 = SingleInstance2.getInstance();
        SingleInstance2 s2 = SingleInstance2.getInstance();
        SingleInstance2 s3 = SingleInstance2.getInstance();
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
    }
}

6.面向对象第二大特征:继承

继承是类与类之间的一种关系
多个类继承单独的某个类,多个类就可以使用单独的这个类的属性和行为了
多个类称为子类(派生类),单独的这个类称为父类(基类或超类)

在Java中,继承的关键字用的是extends

public class 子类名 extends 父类名{}

public class People {
    private String name;
    private int age;
    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 class Student extends People{
    public void study() {
        System.out.println("学生在学习");
    }
}
public class Teacher extends People{
    public void teach() {
        System.out.println("老师在教书育人");
    }
}
public class Test {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        Student s = new Student();
        t.setName("张三");
        t.setAge(20);
        s.setName("lisi");
        s.setAge(49);
        System.out.println(t.getName());
        System.out.println(t.getAge());
        System.out.println(s.getName());
        System.out.println(s.getAge());

    }
}

提高代码复用,减少代码冗余,增强类的功能扩展性
Java中子类更强大

7.继承设计规范

子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的属性和行为应该定义在子类自己里面
如果子类的独有属性、行为定义在夫类中,会导致其他子类也会得到这些属性和行为,这不符合面向对象逻辑

案例:继承的设计规范
在教育管理系统中,存在学生、老师角色

学生信息和行为(名称,年龄,所在班级,查看课表,填写听课反馈)
老师信息和行为(名称,年龄,部门名称,查看课表,发布问题)
定义角色类作为父类包含属性(名称,年龄)行为(查看课表)

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

    public void queryCourse() {
        System.out.println(name+ "查看课程信息");
    }
    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 class Teacher extends Role{
    private String department;
   public void queryQustuin() {
        System.out.println(getName() + "在发布问题");
    }
    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}
public class Studet extends Role{
    private String className;

    public void wtiteInfo() {
        System.out.println(getName() + "学习中");
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }
}
public class Test {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
        s.setAge(20);
        s.setClassName("软件工程");
        s.wtiteInfo();
        System.out.println(s.getAge());
        System.out.println(s.getClassName());
        System.out.println(s.getName());
        s.queryCourse();

        Teacher t = new Teacher();
        t.setAge(44);
        t.setName("lisi");
        t.setDepartment("前端部");
        t.queryQustuin();
        System.out.println(t.getAge());
        System.out.println(t.getName());
        System.out.println(t.getDepartment());
    }
}

8.继承的特点

1.子类可以继承父类的属性和行为,但是子类不能继承父类的构造器

子类不可以继承父类的构造器,父类构造器用于初始化父类对象
子类可以继承父类的私有成员,不能直接访问
子类可以直接使用父类的静态成员

public class ExtendsDemo {
    public static void main(String[] args) {
        Student s = new Student();
//        System.out.println(s.age);
//        s.run();
 		System.out.println(Student.onLineNumber);
        Student.study();
    }
}
class People {
    private int age = 20;
    public static int onLineNumber = 122;
    public static void study() {
        System.out.println("学习");
    }
    private void run() {
        System.out.println("跑");
    }  
}
class Student extends  People{}

2.Java是单继承模式:一个类只能继承一个直接父类
3.Java不支持多继承,但是支持多层继承
4.Java中所有类都是Object类的子类

Java中所有类,要么直接继承了Object,要么默认继承了Object,要么间接继承了Object,Object是祖宗类

在子类方法中访问成员(成员变量、成员方法)满足就近原则
先子类局部范围,然后子类成员范围,然后父类成员范围找,如果父类范围还没找到就会报错

如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类需要在子类中使用中转方法,并且在中转方法中通过super调用

public class ExtendsDemo {
    public static void main(String[] args) {
        Student s = new Student();
        System.out.println(s.name);
        s.showName();

		s.run();
        s.go();
    }
}
class People {
    public String name = "人类";
    public void run() {
        System.out.println("人类可以跑");
    }
}
class Student extends People{
	 public String name = "学生";
	 public void showName() {
	     String name = "局部名称";
	     System.out.println(name);
	     System.out.println(this.name);
	     System.out.println(super.name);
 }
    public void run() {
        System.out.println("学生可以跑");
    }
    public void go() {
        super.run();
    }
 }

9.方法重写

在继承体系中,子类出现了和父类中一摸一样的方法声明,就称子类这个是重写的方法

应用场景
当子类需要父类的功能,但父类的该方法不完全满足自己的需求
子类可以重写父类中的方法

@Override重写注释
@Override是放在重写后的方法上,作为重写是否正确的校验注解
加上该注释后如果重写错误,编译阶段会出现错误提示

建议重写方法都加上@Override注解,代码安全,优雅

方法重写注意事项和要求
重写方法的名称、形参列表必须与被重写方法的一致
私有方法不能重写
子类重写父类方法时,访问权限必须大于或者等于父类(缺省 子类不能重写父类的静态方法,否则会报错

public class Phone {
    public void call() {
        System.out.println("打电话");
    }
    public void sendMessage() {
        System.out.println("发短信");
    }
}
public class NewPhone extends Phone{
//    方法重写
    @Override
    public void call() {
        super.call();
        System.out.println("支持视频通话");
    }
    @Override
    public void sendMessage() {
        super.sendMessage();
        System.out.println("支持语音输入");
    }
}

public class Test {
    public static void main(String[] args) {
        NewPhone n = new NewPhone();
        n.call();
        n.sendMessage();
    }
}

10.子类构造器特点

子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己
子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类无法使用父类的数据
子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化

子类构造器的第一行语句默认 super() ; 默认找父类无参构造器

子类访问父类有参构造器
super调用父类有参构造器的作用:初始化继承自父类的数据
如果父类中没有无参构造器,只有有参构造器会报错,因为子类默认是调用父类无参构造器的
子类构造器中可以通过书写super(…), 手动调用父类的有参构造器

public class People {
    private String name;
    private int age;
    public People() {}
    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 class Student extends People{
    private String clssName;
    public Student(String name, int age, String clssName) {
        super(name, age);
        this.clssName = clssName;
    }

    public String getClssName() {
        return clssName;
    }

    public void setClssName(String clssName) {
        this.clssName = clssName;
    }
}

public class Test {
    public static void main(String[] args) {
        Student s = new Student("zhansgan", 20, "软件工程");
        System.out.println(s.getClssName());
    }
}

11.this和super

this代表本类对象的引用 super:代表父类存储空间的标识

关键字 访问成员变量 访问成员方法 访问构造方法
this this.成员变量
访问本类成员变量
this.成员方法(…)
访问本类成员方法
this(…)
访问本类构造器
super super.成员变量
访问父成员变量
super.成员方法(…)
访问父类成员方法
super(…)
访问父类构造器

案例:在管理系统中,后台创建对象封装数据的时候如果用户没有输入年龄,则默认为20,如果输入则为输入的数据
this(…)和super(…)使用注意点:
子类通过this(…)去调用本类的其他构造器,本类其他构造器会通过super去手动调用父类的构造器,最终韩式会调用父类构造器的
注意:this(…)super(…)都只能放在构造器的第一行,所以二者不能共存在同一个构造器中

public class Student {
    private String name;
    private int age;
    public Student(){}
    public Student(String name) {
    		// 借用兄弟构造器
            this(name, 20);
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 class Test {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 12);
        System.out.println(s1.getAge());
        System.out.println(s1.getName());

        Student s2 = new Student("李四");
        System.out.println(s2.getAge());
        System.out.println(s2.getName());
    }
}

你可能感兴趣的:(Java,JavaSE基础,java,开发语言)