Java开发基础_03

五. 面向对象

面向过程 : 以函数为最小单位(方法),数据独立于函数之外,以过程步骤为主(怎么做)—执行者

面向对象 : 以类对象为最小单位,类包括数据+方法,是以对象为主(谁来做)—指挥者

1. 面向对象的基本特征

  • 封装 , 继承 , 多态

2. 类和对象

    • 类 : 是一类具有相同特性的事物的抽象描述,是一组相关属性和行为的集合,可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该事物
    • 属性 : 状态信息
    • 行为 : 该事物能做什么
    举例:小猫
    属性:名字,颜色,体重
    行为:走,跑,叫
    
  • 对象 :

    • 对象 : 是一类事物的具体的体现,对象是类的一个实例,必然具备该事物的属性和行为
    举例:小猫
    属性:tom,yellow,5KG
    行为:贴墙走,喵喵叫
    
  • 类与对象的关系

    • 类是对一类事物的描述,是抽象的
    • 对象是一类事物的实例,是具体的
    • 类是对象的模板,对象是类的实体
  • 创建类

    • 成员方法 : 对应事物的一些行为
    • 成员变量 : 对应事物的属性
  • 类的定义

    • public class 类名 {//成员变量 //成员方法}
    • 定义类 : 就是定义类的成员,包括成员变量和成员方法
    • 成员变量 : 和以前定义变量几乎是一样的,只不过位置发生了改变,在类中,在方法外
    • 成员方法 : 和以前写的main方法格式类似,只不过功能和形式更丰富,在类中,在方法外
    package com.kgc01;
    public class Demo01Person {
          
          
            //成员变量
            String name;        //姓名
            int age;            //年龄
            String gender;      //性别
            //成员方法
            public void walk(){
          
          
                System.out.println("走路");
            }
            public String display(){
          
          
                return "名字是:"+name+",年龄是:"+age+",性别是:"+gender;
            }  
    }
    
  • 对象的创建

    • new 类名() //匿名对象
    • 类名 对象名 = new 类名(); //把创建的对象保存下来
    • 对象是引用数据类型
    package com.kgc01;
    public class PersonTest {
          
          
        public static void main(String[] args) {
          
          
            //创建一个对象
            Demo01Person p1=new Demo01Person();
            p1.name="小红";
            p1.age=18;
            p1.gender="女";
            p1.walk();
            p1.display();
            System.out.println(p1.display());
        }
    }
    
    //在一个java文件里创建
    package com.kgc01;
    class Student{
          
          
        String name;
        public void study(){
          
          
            System.out.println("好好学习,天天向上");
        }
    }
    public class TestStudent {
          
          
        public static void main(String[] args) {
          
          
            Student s1 = new Student();
            s1.name="张三";
            System.out.println(s1.name);
            s1.study();
        }
    }
    

3. 成员变量

  • 成员变量

    • 分类

      • 实例变量 : 也叫对象属性,属于某个对象的,通过对象来使用
      • 类变量 : 属于整个类的,不是属于某个实例
    • 声明一个实例变量

      • [修饰符] class 类名 {
      • [修饰符] 数据类型 属性名; //属性有默认值;
      • [修饰符] 数据类型 属性名 = 值; //属性有初始值;
      • }
      • 属性的类型可以是任意类型,基本数据类型,引用数据类型(类,接口,数组)
    • 使用实例变量

      • 实例变量在本类中可以直接使用
      package com.kgc01;
      public class circle {
              
              
      double r;
          public double getArea(){
              
              
          return 3.14*r*r;
          }
      }
      
      • 实例变量在其他类中使用,需要通过对象名.实例变量的方式
      package com.kgc01;
      public class TestCircle {
              
              
          public static void main(String[] args) {
              
              
              circle c = new circle();
              c.r=5;
              System.out.println("面积是:"+c.getArea());
          }
      }
      

4. 实例变量

  • 实例变量的特点

    • 成员变量有默认值
    • 基本数据类型
      • 整数(byte , short , int , long) 0
        • 浮点数(float , double) 0.0
        • 字符(char) ‘\u0000’
        • 布尔(boolean) false
      • 引用数据类型(数组,类,接口,字符串) null
    • 实例变量的值,相对每个对象来说都是独立的
  • 实例变量的赋值

    • 在声明属性时,显式赋值,在创建每个对象后,这个属性的值就不是默认值了,就是这个初始值
    • 通过对象属性来赋值,
  • 实例变量和局部变量的区别

    • 在类中的位置不一样

      • 实例变量 : 在类中方法外
      • 局部变量 : 在方法中或者方法声明上(形式参数)
    • 作用范围不一样

      • 实例变量 : 在类中直接使用,其它类中可以通过"对象名.实例变量来使用
      • 局部变量 : 当前方法的作用域
    • 初始化的值不同

      • 实例变量有默认值
      • 局部变量没有默认值,必须先定义赋值再使用
    • 在内存中的位置不同

      • 实例变量 : 堆内存
      • 局部变量 : 栈内存
    • 生命周期不同

      • 实例变量 : 随着对象的创建或类的加载而存在,随着对象的消失而消失
        • 就是说没有创建对象,就不会在堆内存中分配空间,创建一个就会分配一个
      • 局部变量 : 随着方法的调用而存在,随着方法的调用完而消失
        • 就是说,方法没有被调用时,该局部变量不会再栈内存中分配空间,调用一次分配一次
      package com.kgc01;
      //需求: 声明员工类, 包含姓名 ,性别,薪资,三个实例变量,  并创建员工对象,打印员工信息
      class Staff{
              
                                          //声明员工类
          String name;                        //姓名
          String gender;                      //性别
          double price;                       //薪资
      }
      public class Demo03 {
              
              
          public static void main(String[] args) {
              
              
              Staff staff = new Staff();      //创建员工对象
              staff.name="张三";
              staff.gender="男";
              staff.price=10000;
              System.out.println("姓名:"+staff.name);
              System.out.println("性别:"+staff.gender);
              System.out.println("薪资:"+staff.price);
          } 
      
      }
      

5. 成员方法

  • 成员方法

    • 方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元,把一个功能封装成一个方法,可以实现代码的重用,减少代码量

    • 方法的使用原则

      • 必须先声明后使用
      • 不调用不执行,调用一次执行一次,方法压栈一次
    • 成员方法的分类

      • 实例方法 : 属于对象的方法,由对象来调用
      • 静态方法 : 也叫类方法,属于整个类的,不是属于某个实例,由类名来调用,后面有static
    • 语法格式

    修饰符 返回值类型 方法名([参数列表:参数类型1 参数名1,参数类型2 参数名2...]){
    
    
    方法体;
    - [return 返回值;]
    - }
  • 修饰符 : public 目前是固定的写法
  • 返回值类型 : 表示方法运行的结果的数据类型,方法执行后将结果返回给调用者
    • 基本数据类型
    • 引用数据类型
    • 无返回值类型 void
  • 方法名 : 见名知意小驼峰
  • 参数列表 : 方法中使用的数据类型,需要通过参数传递的形式将数据传递过来,可以是基本数据类型,也可以是引用数据类型,也可以没有参数什么都不写
  • 方法体 : 实现具体功能的代码
  • return : 结束方法,并将方法的结果返回回去
    • 如果返回值类型不是void,方法体中必须有return返回值,返回值的类型要与声明的返回值的类型一致
    • 如果返回值的类型时void,return后不用跟返回值,甚至可以不写return语句
    • return语句后,不写其他代码,否则会报错
  • 方法声明时,必须在类,方法外
  • 方法的调用
    • 单独调用
      • 对象名.方法名(参数);
    • 输出调用
      • System.out.println(对象名.方法名(参数));
    • 赋值调用
      • 数据类型 变量名 = 对象名.方法名(参数);
 package com.kgc02;
 //定义计算两个整数和的方法,返回值类型,计算的结果是int,参数,两个都是int类型
 public class Demo01Add {
    
    
     public static void main(String[] args) {
    
    
         Add a = new Add();
         int sum = a.getAdd(1,2);
         //第一种
         System.out.println("sum = "+sum);
         //第二种
         System.out.println(a.getAdd(2,3));
     }
 }
 //加法类
 class Add{
    
    
     //方法
     public int getAdd(int a,int b){
    
    
         return a+b;
     }
 }
 ```

- 形参 : 在定义方法时,方法名后面括号中的变量名称为形式参数(简称形参),即形参出现在方法定义中

- 实参 : 调用者方法中调用另一个方法时,方法名后边括号中的参数称为实际参数(简称实参),即实参出现在调用者方法中

- 总结 : 调用时,需要通过方法名来识别调用哪个方法

- 调用时,需要传"实参",实参的个数,类型顺序,需要与形参列表一一对应,如果方法没有形参,就不需要也不能传实参

- 调用时,如果方法有返回值,可以接受或处理返回值的结果,如果方法返回值的类型是void,不需要也不能接收和处理返回值结果

```java
package com.kgc02;
//比较两个整数是否相等: 需要定义一个方法,两个参数, 有返回值
class Equals{
    
    
   public boolean getEqual(int a,int b){
    
    
       return a==b;
   }
}
public class Demo02Equal {
    
    
   public static void main(String[] args) {
    
    
       Equals equals = new Equals();
       System.out.println(equals.getEqual(1,1));
   }
}
  • 可变参数

    • 一个方法只能有一个可变参数
    • 可变参数必须是形参列表的最后一个
    package com.kgc02;
    
    public class Demo03 {
          
          
        public static void main(String[] args) {
          
          
            //实例化对象
            Sum s = new Sum();
            int array[] = {
          
          1,2,3,4,5,6,7,8};
            System.out.println(s.mySum(array));
            System.out.println(s.mySum2(array));
        }
    }
    class Sum{
          
          
        public int mySum(int[] a){
          
          
            int sum=0;
            for (int i=0;i<a.length;i++){
          
          
                sum+=a[i];
            }
            return sum;
        }
        public int mySum2(int...arr){
          
          
            int sum=0;
            for (int i=0;i<arr.length;i++){
          
          
                sum+=arr[i];
            }
            return sum;
        }
    }
    
    //定义求1-n个整数中的最大值
    package com.kgc02;
    import java.util.Arrays;
    public class Demo04Max {
          
          
        public static void main(String[] args) {
          
          
            int[] arr = new int[]{
          
          3,4,56,67,81,34,70};
            Max max = new Max();
            System.out.println(max.myMax(arr));
            System.out.println(max.myMax(1,3,454567,768,4356,678,435,4563));
        }
    }
    class Max{
          
          
        public int myMax(int...a){
          
          
            Arrays.sort(a);
            return a[a.length-1];
        }
    }
    

6. 方法的重载

  • 在同一个类中,允许存在一个以上的同名方法,只要让他们的参数列表不同即可,与修饰符和返回值类型无关

  • 参数列表 : 数据类型个数不同,数据类型不同,数据类型顺序不同

  • 重载方法的调用 : JVM是通过方法的参数列表调用不同的方法

    //比较两个数据是否相等,分别为两个byte类型,两个short类型,两个long类型
    package com.kgc02;
    
    public class Demo05Equals {
          
          
        public static void main(String[] args) {
          
          
            MyEqual myEqual = new MyEqual();
            byte a1=10;
            byte a2=20;
            System.out.println(myEqual.equals(a1,a2));
            short b1=10;
            short b2=10;
            System.out.println(myEqual.equals(b1,b2));
            int c1=10;
            int c2=20;
            System.out.println(myEqual.equals(c1,c2));
            long d1=10;
            long d2=10;
            System.out.println(myEqual.equals(d1,d2));
        }
    }
    class MyEqual{
          
          
        public String equals(byte a,byte b){
          
          
            return a==b?"相等":"不相等";
        }
        public String equals(short a,short b){
          
          
            return a==b?"相等":"不相等";
        }
        public String equals(int a,int b){
          
          
            return a==b?"相等":"不相等";
        }
        public String equals(long a,long b){
          
          
            return a==b?"相等":"不相等";
        }
    }
    

7. 封装

  • 封装

    • 隐藏对象内部的复杂性,只对外公开简单的接口,便与外界访问,从而提高系统的可扩展性,可维护性,通俗的将就是把该隐藏的隐藏起来,该暴露的暴露出来,这就是封装的设计思想
  • 属性的封装

    • 将属性隐藏起来,若需要访问某个属性,我们只需要提供公共的方法对其访问
  • 属性封装的目的

    • 隐藏类的实现细节
    • 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里面加入控制逻辑,限制对成员变量的不合理访问
    • 可以进行数据的检查,从而有利于保证对象信息的完整性
    • 便于修改,提高代码的可维护性
  • 实现步骤

    • 使用private 修饰成员变量
      • private 数据类型 变量名;
    • 对外提供 getXXX 方法 setXXX方法,可以访问成员变量
  • 权限修饰符

    修饰符 在同一个类中 在同一个包中 子类中 任何地方
    private 可以 不可以 不可以 不可以
    默认修饰符 可以 可以 不可以 不可以
    protected 可以 可以 可以 不可以
    public 可以 可以 可以 可以
    • 对于类成员 : 四种权限修饰符都可以使用
    • 对于外部的类 : 只能使用public和缺省两种
    package com.kgc01;
    //定义一个学生类Student,声明 姓名和成绩,实例变量,私有化,提供get/set方法,getinfo方法用于返回学生的对象信息
    public class Student {
          
          
        private String name;
      private int score;
        public void setName(String n){
          
          
            name=n;
        }
        public String getName(){
          
          
            return name;
        }
        //----------------------------------------------------------
        public void setScore(int s){
          
          
            score=s;
        }
        public int getScore() {
          
          
            return score;
        }
        //----------------------------------------------------------
        public String getInfo(){
          
          
            return "姓名:"+name+"\t"+"成绩:"+score;
        }
    }
    
    package com.kgc01;
    import java.util.Scanner;
    
    //定义一个测试类TestStudent,main中创建一个可以装3个学生的对象的数组,并且按照学生成绩排序,显示学生信息
    public class Test {
          
          
        public static void main(String[] args) {
          
          
            Scanner sc = new Scanner(System.in);
            //创建一个可以装3个学生的对象的数组
            Student[] s = new Student[3];
            //赋值
            s[0]=new Student();
            s[0].setName("张三");
            s[0].setScore(89);
    
            s[1]=new Student();
            s[1].setName("李四");
            s[1].setScore(98);
    
            s[2]=new Student();
            s[2].setName("王五");
            s[2].setScore(69);
            //先打印目前的顺序
            for (int i = 0; i < s.length; i++) {
          
          
                System.out.println(s[i].getInfo());
            }
            System.out.println("--------------------");
            //冒泡排序
            for (int i = 0; i < s.length; i++) {
          
          
                for (int j = 0; j < s.length-i-1; j++) {
          
          
                    if (s[j].getScore()>s[j+1].getScore()){
          
          
                        Student temp = s[j];
                        s[j]=s[j+1];
                        s[j+1]=temp;
                    }
                }
            }
            for (int i = 0; i < s.length; i++) {
          
          
                System.out.println(s[i].getInfo());
            }
        }
    }
    

8. 构造器

  • 构造器

    • 又称为构造方法,因为跟方法长得很像,和方法还有区别
    • 作用
      • 要创建一个类的实例对象,必须调用一个对象的构造器,来完成类的实例初始化过程,实例初始化过程就是为实例变量赋初始值的过程
      • 无论是否自定义构造方法,所有的类都有一个无参构造方法,一旦自定义了构造方法,就不送
    • 格式
      • 修饰符 构造器名(){实例初始化代码}
      • 修饰符 构造器名(参数列表){实例初始化代码}
    public class Test01Student {
          
          
        private String name;
        private int age;
        //无参构造
        public Test01Student(){
          
          
            System.out.println("无参构造");
        }
        //有参构造
        public Test01Student(String n,int a){
          
          
            name=n;
            age=a;
        }
    
    • 注意事项 :
      • 构造器的名必须与他所在的类名相同
      • 他没有返回值,所有不需要返回值类型,甚至不需要void
      • 如果你不需要提供构造器,系统会给出无参构造器,并且该构造器的修饰符默认与类的修饰符相同
      • 如果你提供了构造器,系统将不再提供无参构造器,除非你自己定义
      • 构造器是可以重载的,即定义参数,也可以不定义参数
      • 构造器不能被 static final,…修饰
    练习:
    package com.kgc01;
    /*1. 声明一个员工类:
        1. 属性: 编号,姓名,薪资,性别, 要求属性私有化,提供get / set方法
        2. 提供无参构造和有参构造
        3. 提供 getInfo()
    2. 测试类中main中,分别用无参构造和有参构造 创建员工对象, 调用getInfo方法
    */
    public class Test02Emp {
          
          
        private int id;
        private String name;
        private double price;
        private String gender;
        //无参
        public Test02Emp(){
          
          }
        //有参
        public Test02Emp(int a,String b,double c,String d){
          
          
            id=a;
            name=b;
            price=c;
            gender=d;
        }
        public int getId() {
          
          
            return id;
        }
        public void setId(int id) {
          
          
            this.id = id;
        }
        public String getName() {
          
          
            return name;
        }
        public void setName(String name) {
          
          
            this.name = name;
        }
        public double getPrice() {
          
          
            return price;
        }
        public void setPrice(double price) {
          
          
            this.price = price;
        }
        public String getGender() {
          
          
            return gender;
        }
        public void setGender(String gender) {
          
          
            this.gender = gender;
        }
        public String getInfo(){
          
          
            return "编号:"+getId()+"\t"+"姓名:"+getName()+"\t"+"薪资:"+getPrice()+"\t"+"性别:"+getGender()+"\t";
        }
    }
    
    
    package com.kgc01;
    //2. 测试类中main中,分别用无参构造和有参构造 创建员工对象, 调用getInfo方法
    //    private int id;
    //    private String name;
    //    private double price;
    //    private String gender;
    public class Test02Demo {
          
          
        public static void main(String[] args) {
          
          
            Test02Emp emp = new Test02Emp();
            emp.setId(1);
            emp.setName("李四");
            emp.setPrice(2000);
            emp.setGender("女");
            System.out.println(emp.getInfo());
    
            Test02Emp emp1 = new Test02Emp(2,"张三",1000,"男");
            System.out.println(emp1.getInfo());
        }
    }
    
  • this

    • 我们发现setXXX方法中形参名和构造器形参名不符合见名知意的规定,如果非要修改成和成员变量名一致的,会赋值失败,只能使用this关键字来解决重名问题
    • this含义
      • this代表当前对象引用(地址值),即对象自己的引用
      • this可以用于构造器中,表示正在创建的那个实例对象,即正在new谁,this就代表谁
      • this可以用在实例方法中,表示该调用方法的对象,即谁在调用,this就代表谁
    • 格式
      • this.成员变量 或 this.成员方法
        public Test02Emp(int id, String name, double price, String gender) {
          
          
            this.id = id;
            this.name = name;
            this.price = price;
            this.gender = gender;
        }
    
  • java语言编写类的标准规范

    public class ClassName{
          
          
    //成员变量
    //构造方法
    	//无参构造  必须有
    	//有参构造  建议有
    //setXXX()
    //getXXX()
    //其他成员方法
    }
    

9. 包

    • 包的作用
      • 避免类的重名,有了包之后,类的全名就变为了 包.类名
      • 分类组织管理众多的类
        • 常用的类
          • java.lang 包中有 String , Math , Integer , System
          • java.util 实用工具类 集合,日期,数组相关,输入相关,随机相关
          • java.sql 数据库相关
          • java.awt 窗口相关
      • 控制某些类型或成员的可见范围
    • 使用其他包的类
      • 前提 : 被使用的类或成员的权限是大于缺省的
      • 使用类的全名称 java.util.Scanner import = new java.util.Scanner(System.in)
      • 使用import语句,代码可以使用简称

10. 继承

  • 继承的由来

    • 多个类中存在相同的属性和行为,将这些内容抽取到单独的一个类中,那么多个类中无需再定义这些属性和行为,只需要和抽取出来的类构造某种关系
    • 其中多个类可以成为子类,也叫派生类,多个类抽取出来的这个类称为父类,超类或基类
    • 继承描述的是事物之间的所属关系,这种关系是 is a 的关系,如:猫是动物,狗也是动物,父类就能更通用,子类更具体,我们通过继承,可以使多种事物之间形成一种关系体系
  • 继承 : 就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性,相同的行为

  • 好处 :

    • 提高代码的复用性
    • 提高代码的可扩展性
    • 类与类之间产生了关系,是学习多态的前提
  • 格式 :

    • 通过extends 关键字,可以声明一个子类继承另外一个父类
      • 修饰符 class 父类{}
      • 修饰符 class 子类 extends 父类
    package com.kgc02;
    /*
    定义动物类,作为父类
     */
    public class Animal {
          
          
        //定义name属性
        public String name;
        //定义age属性
        public int age;
        //定义动物吃东西的方法
        public void eat(){
          
          
            System.out.println(age+"岁的"+name+"在吃东西--animal");
        }
    }
    -----------------------------------------------------------------------------
    
    
    package com.kgc02;
    //定义猫类,继承动物
    public class Cat extends Animal{
          
          
        //定义一个猫抓老鼠的方法
        public void catchMouse(){
          
          
            System.out.println("抓老鼠--cat");
        }
    }
    -----------------------------------------------------------------------------
    
    package com.kgc02;
    
    public class Test01 {
          
          
        public static void main(String[] args) {
          
          
            //创建一个猫类对象
            Cat cat = new Cat();
            //为猫类对象name属性进行赋值
            cat.name = "Tom";
            //为猫类对象age属性进行赋值
            cat.age = 1;
            //调用猫类方法
            cat.catchMouse();
            //调用毛类继承来的eat方法
            cat.eat();
        }
    }
    
  • 继承的特点 :

    • 成员变量
      • 私有化 private
        • 父类中的成员,无论是共有的还是私有的,均会被子类继承
        • 子类虽然会继承父类的成员,但子类不能对继承的私有的成员直接访问,可以通过继承的公有的方法进行访问
      • 成员变量不重名没有影响,如果重名会有影响,如果声明的是子类对象,那么重名的成员变量调用的就是子类的
      • 如果需要用父类的,使用super关键字,类似于this
        • super.父类成员变量名
    • 成员方法
      • 成员方法不重名
      • 成员方法重名----重写override
        • 如果子类,父类中出现重名的成员方法,这是访问是一种特殊情况,叫做方法的重写
      • 总结
        • 在父子类的继承关系中,创建子类对象,访问成员方法的规则
          • 创建的对象是谁,就优先用谁,如果没有则向上找
        • 注意事项
          • 无论成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类
        • 重写
          • 在继承关系中,方法的名称一样,参数列表也一样,也叫覆盖,覆写
          • 重载 : 方法的名称一样,参数列表不一样
          • 子类根据需要,定义特定自己的行为,即沿袭父类的功能名称,有根据子类的需要重新实现父类的方法,从而增强可扩展性
    • 总结
      • 父类
        • @Override 卸载方法前面,用来检测是否有效的正确的覆盖重写
      • 子类方法的返回值类型 必须小于等于父类方法的返回值类型(小于其实就是是它的子类)
        • java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String 就是Object的子类
        • 如果返回值类型是基本数据类型和void,那么必须相同
      • 子类方法的权限必须大于等于父类方法的权限修饰符
        • public > protected > 缺省 > private
      • 几种特殊的方法不能重写
        • 静态方法不能重写
        • 私有在子类中不可见的方法不能 重写
        • final方法不能重写
    //声明父类:Person类 包含属性:姓名,年龄,性别 属性私有化,get/set 包含getinfo方法
    package com.kgc03;
    public class Person {
          
          
        private String name;
        private int age;
        private String 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;
        }
        public String getInfo(){
          
          
            return "姓名:"+name+"\t"+"年龄:"+age+"\t"+"性别:"+gender+"\t";
        }
    }
    //声明子类:Student类 继承Person类,新增属性score,属性私有化get/set 包含getinfo方法
    package com.kgc03;
    public class Student extends Person {
          
          
        private int score;
        public int getScore() {
          
          
            return score;
        }
        public void setScore(int score) {
          
          
            this.score = score;
        }
    
        @Override
        public String getInfo() {
          
          
            return super.getInfo()+"成绩:"+getScore()+"\t";
        }
    }
    //声明子类:Teacher类 继承Person类,新增属性salary,属性私有化get/set 包含getinfo方法
    package com.kgc03;
    public class Teacher extends Person{
          
          
        private int salary;
        public int getSalary() {
          
          
            return salary;
        }
        public void setSalary(int salary) {
          
          
            this.salary = salary;
        }
        @Override
        public String getInfo() {
          
          
            return super.getInfo()+"薪资:"+salary+"\t";
        }
    }
    //测试类
    package com.kgc03;
    
    public class Test03 {
          
          
        public static void main(String[] args) {
          
          
            Student st = new Student();
            st.setName("张三");
            st.setAge(18);
            st.setGender("男");
            st.setScore(100);
            System.out.println(st.getInfo());
            Teacher t = new Teacher();
            t.setName("李四");
            t.setAge(28);
            t.setGender("女");
            t.setSalary(10000);
            System.out.println(t.getInfo());
        }
    }
    
    • 构造方法
      • 构造方法的名字是与类名一致的,所以子类是无法继承父类构造方法的
      • 构造方法的作用,是初始化成员变量的,所以子类的初始化过程中必须先执行父类的初始化动作,子类的构造方法中默认有一个super(),所以调用父类的构造方法,父类成员变量初始化后才可以给子类使用

11. 静态

  • static

    • 是一个成员修饰符,可以修饰类的成员,成员变量,成员方法

    • 被修饰的成员是属于类的,而不是单单属于某个对象,可以不用靠创建对象来使用

    • 静态方法

      • 可以叫类方法,也可以叫静态方法
      • 语法
      [其他修饰符] static 返回值类型 方法名([参数列表]){
              
              
          //方法体
      }
      
      • 在本类中,静态的方法可以直接访问,静态方法和静态变量
      • 在其他类中,可以使用 类名.方法 进行调用,也可以使用 对象名.方法 ,(推荐使用类名.方法名)
      • 在静态方法中不能出现this,也不能直接使用本类的非静态成员,相反,非静态的实例成员方法可以直接使用访问静态的类变量和静态方法
      • this,非静态的成员,这些都需要创建对象时才能使用,而静态方法调用时可以没有对象,也就是说静态方法只能访问静态变量
      package com.kgc01;
      
      public class Demo01 {
              
              
          public static void main(String[] args) {
              
              
              Son s = new Son();
              s.fun();  //有警告,没错误也可以运行 
              Son.fun();  //建议使用 类名.方法名
              //Son.method();     非静态不能使用
              s.method();
          }
      }
      class Son{
              
              
          private int a;
          private static int b;
          public static void fun(){
              
              
      //        静态方法只能访问静态变量----否则报错
      //        System.out.println(a);
      //        System.out.println(this.a);
      //        method();
      
              System.out.println(b);
              System.out.println("Son:fun()");
          }
          public void  method(){
              
              
              System.out.println("Son:method()");
          }
      }
      
    • 静态变量

      • 也叫类变量,静态变量
      • 类变量的值和类信息一起存在于方法区中
      • 它的get/set也是static的
      • 在static方法中如果有局部变量与类变量重名,使用 '类名.成员变量’进行区分
      • 静态变量是成员变量的一种,静态变量存储在方法区中,则它在类加载时就会进行初始化,所以静态变量访问的时候不需要创建实例(对象),直接可以通过类名来访问
      package com.kgc01;
      public class Demo02 {
              
              
          public static void main(String[] args) {
              
              
              //无需创建对象
              //静态变量是成员变量的一种,静态变量存储在方法区中,则它在类加载时就会进行初始化
              Chinese c1 = new Chinese("小红");
              Chinese c2 = new Chinese("小明");
              System.out.println("国家:"+c1.getCountry()+",姓名:"+c1.getName());
              System.out.println("国家:"+c2.getCountry()+",姓名:"+c2.getName());
      
              c1.setCountry("中国");    //两个对象共享,一个对象修改,会影响另一个对象
              System.out.println("国家:"+c1.getCountry()+",姓名:"+c1.getName());
              System.out.println("国家:"+c2.getCountry()+",姓名:"+c2.getName());
      
              // 所以静态变量访问的时候不需要创建实例(对象),直接可以通过类名来访问
              Chinese.setCountry("China");    //通过类名. 访问可读性更好
              System.out.println("国家:"+Chinese.getCountry()+",姓名:"+c1.getName());
              System.out.println("国家:"+Chinese.getCountry()+",姓名:"+c2.getName());
          }
      }
      class Chinese{
              
              
          //静态成员属于整个类所有,类的所有对象所共享
          private static String country="中华人民共和国";
          //非静态不会被共享
          private String name;
          public Chinese(String name) {
              
              
              this.name = name;
          }
          public static String getCountry() {
              
              
              return country;
          }
          public static void setCountry(String country) {
              
              
              Chinese.country = country;
          }
          public String getName() {
              
              
              return name;
          }
          public void setName(String name) {
              
              
              this.name = name;
          }
      }
      

12. 抽象类

  • 抽象类

    • 抽象 : 即不具体,或无法具体

    • 抽象方法 : 没有方法体的方法

    • 抽象类 : 被abstract修饰的抽象类

      • 抽象类
      [权限修饰符] abstract class 类名{
              
              
          }//父类
      [权限修饰符] abstract class 类名 extends 父类{
              
              
          }
      
      • 抽象方法
      [其他修饰符] abstract 返回值类型 方法名 ([形参列表]); //注意:抽象方法没有方法体
      
    • 继承抽象类的子类,必须重写父类的抽象方法,否则该子类也必须声明为抽象类,最终必须有子类实现该父类的抽象方法,否则,从最初的的父类到最终的子类都不能创建对象,失去意义

      package com.kgc01;
      abstract class Animal{
              
              
          public abstract void run();
      }
      class Cat extends Animal{
              
              
          @Override
          //重写----实现父类没有实现的方法
          public void run() {
              
              
              System.out.println("小猫在墙上走");
          }
      }
      public class Demo03 {
              
              
          public static void main(String[] args) {
              
              
              //创建子类对象
              Cat cat = new Cat();
              //调用run方法
              cat.run();
          }
      }
      
    • 注意事项

      • 抽象类不能创建对象,如果创建编译无法通过而报错,只能创建非抽象子类的对象
      • 抽象类中可以有构造方法,是供子类创建对象时,初始化父类成员变量使用的
      • 抽象类中不一定包含抽象方法,担忧抽象方法的类必定是抽象类
      • 抽象类的子类,必须重写父类的所有抽象方法,否则编译无法通过,除非该子类也是抽象类
      package com.kgc01;
      abstract class Graphic{
              
              
          private String name;
          public Graphic(String name) {
              
              
              this.name = name;
          }
          public abstract double getArea();
          public abstract double getPerimeter();
          public String getInfo(){
              
              
              return "名称:"+name+"\t"+"面积:"+getArea()+"\t"+"周长:"+getPerimeter()+"\t";
          }
      }
      
      class Circle extends Graphic{
              
              
          private double radius;
          public Circle(String name, double radius) {
              
              
              super(name);
              this.radius = radius;
          }
          @Override
          public double getArea() {
              
              
              return radius*radius*3.14;
          }
          @Override
          public double getPerimeter() {
              
              
              return radius*6.28*100/100;
          }
          public String getInfo() {
              
              
              return super.getInfo()+"半径:"+radius+"\t";
          }
      }
      
      class Rectange extends Graphic{
              
              
          public double length;
          public double width;
      
          public Rectange(String name, double length, double width) {
              
              
              super(name);
              this.length = length;
              this.width = width;
          }
          @Override
          public double getArea() {
              
              
              return length*width;
          }
          @Override
          public double getPerimeter() {
              
              
              return 2*(length+width);
          }
          public String getInfo() {
              
              
              return super.getInfo()+"长:"+length+"\t"+"宽:"+width+"\t";
          }
      }
      
      public class Demo04 {
              
              
          public static void main(String[] args) {
              
              
              Rectange rec = new Rectange("长方形",10,20);
              System.out.println(rec.getInfo());
      
              Circle cir = new Circle("圆",10);
              System.out.println(cir.getInfo());
          }
      }
      
      package com.kgc01;
      /*
      练习:
      1. 声明抽象父类: Person,包含抽象方法:
          1. public abstract void walk();
          2. public abstract void ea();
      2. 声明子类 Man, 继承 Person
          1. 重写walk(): 大步流星的走
          2. 重写eat(): 狼吞虎咽的吃饭
          3. 新增方法: public void smoke() 吞云吐雾
      3. 声明子类 Woman, 继承Person
          1. 重写walk(): 婀娜多姿的走
          2. 重写eat(): 细嚼慢咽的吃饭
          3. 新增方法: public void buy() 买买买
      4. 测试类中创建子类对象,调用 方法测试
       */
      abstract class Person{
              
              
          public abstract void walk();
          public abstract void eat();
      }
      
      class Man extends Person{
              
              
          @Override
          public void walk() {
              
              
              System.out.println("大步流星的走");
          }
          @Override
          public void eat() {
              
              
              System.out.println("狼吞虎咽的吃饭");
          }
          public void smoke(){
              
              
              System.out.println("吞云吐雾");
          }
      }
      
      class Woman extends Person{
              
              
          @Override
          public void walk() {
              
              
              System.out.println("婀娜多姿的走");
          }
          @Override
          public void eat() {
              
              
              System.out.println("细嚼慢咽的吃饭");
          }
          public void buy(){
              
              
              System.out.println("买买买");
          }
      }
      
      public class Demo05 {
              
              
          public static void main(String[] args) {
              
              
              Man man = new Man();
              man.walk();
              man.eat();
              man.smoke();
      
              System.out.println("-----------------------");
      
              Woman woman = new Woman();
              woman.walk();
              woman.eat();
              woman.buy();
          }
      }
      

13. 多态

  • 多态

    • 多态是指同一行为,具有多个不同的表现形式

    • 前提

      • 继承父类或实现接口
      • 方法的重写
      • 父类引用指向子类对象
      父类类型 变量名 = new 子类对象;
      变量名.方法名();		//这个方法是父类中声明的,子类中重写的方法
      
    • 多态的体现

      • 编译时,看父类,只能调用父类声明的方法,不同的调用子类扩展的方法
      • 运行时,看子类,一定是执行子类重写的方法体
      package com.kgc02;
      abstract class Animal2{
              
              
          public abstract void eat();
      }
      
      class Cat extends Animal2{
              
              
          @Override
          public void eat() {
              
              
              System.out.println("吃鱼");
          }
          public void catchMouse(){
              
              
              System.out.println("捉老鼠");
          }
      }
      
      class Dog extends Animal2{
              
              
          @Override
          public void eat() {
              
              
              System.out.println("吃骨头");
          }
      }
      
      public class Demo01 {
              
              
          public static void main(String[] args) {
              
              
              //多态的形式创建对象
              Animal2 a1 = new Cat();
              //调用Cat中的eat
              a1.eat();
              //a1.catchMouse();是子类的扩展的方法,父类中没有
              Animal2 a2 = new Dog();
              a2.eat();
      
              showAnimal2Eat(a1);
              showAnimal2Eat(a2);
          }
      
      //   public static void showCatEat(Cat a){
              
              
      //        a.eat();
      //    }
          public static void showAnimal2Eat(Animal2 b){
              
              
              b.eat();
          }
      }
      
    • 多态的好处

      • 多态参数
        • 在实际开发过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性和便利性
      • 多态数组
        • 家里养了两只猫,两条狗,想要统一管理他们的对象,可以使用多态数组
      package com.kgc02;
      
      public class Demo02 {
              
              
          public static void main(String[] args) {
              
              
              Animal2[] all = new Animal2[4];  //可以存储各种Animal子类对象
              all[0]=new Cat();
              all[1]=new Cat();
              all[2]=new Dog();
              all[3]=new Dog();
              for (int i = 0; i < all.length; i++) {
              
              
                  all[i].eat();
              }
          }
      }
      
      //练习
      //声明一个抽象父类Traffic,包含抽象方法 public abstract void driver()
      //声明子类Car,Bicycle,并重写dirver方法
      //在测试类main中,创建一个数组,有各种交通工具,遍历调用driver方法,模拟马路上跑的各种交通工具
      package com.kgc02;
      
      abstract class Traffic{
              
              
          public abstract void driver();
      }
      class Bicycle extends Traffic{
              
              
          @Override
          public void driver() {
              
              
              System.out.println("自行车");
          }
      }
      class Car extends Traffic{
              
              
          @Override
          public void driver() {
              
              
              System.out.println("汽车");
          }
      }
      public class Demo03 {
              
              
          public static void main(String[] args) {
              
              
              Traffic[] traffic = new Traffic[]{
              
              new Car(),new Car(),new Bicycle(),new Bicycle()};
              for (int i = 0; i < traffic.length; i++) {
              
              
                  traffic[i].driver();
              }
          }
      }
      
    • 父子类之间的类型转换

      • 向上转型

        • 多态本身是子类类型向上转换的过程,这个过程是默认,父类的引用,指向子类的对象,这就是向上转型
      • 向下转型

        • 父类类型向子类类型向下转换的过程,这个过程是强制的
        子类类型 变量名 = (子类类型) 父类变量名;
        
        //向上转型
        Animal a = new Cat();   
        //向下转型 
        Cat c = (Cat) a;
        
    • instanceof

      • 为避免ClassCastException的发生,给引用变量做类型的校验,只要用instanceof判断返回为true,那么强制转换类型就是安全的,不会报错

        变量名/对象名 instanceof 数据类型;
        //如果属于就返回true,如果不属于就返回false
        
        Aniamls a = new Dog();
        if(a instanceof Cat){
                  
                  
            Cat cc = (Cat) a;
            cc.catchMouse();
        }else if(a instanceof Dog){
                  
                  
            Dog dd = (Dog) a;
            dd.watchHouse();
        }
        

14. Object类

  • 它是所有类的根类,即所有类的父类

  • toString() 默认情况返回的是对象进行时的类型,重写返回对象的详细信息来代替之前的getInfo

  • equals() 判断两个对象是否为同一个对象 和==类似

    package com.kgc03;
    
    public class Person {
        private String name;
        private int age;
    
        public Person(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;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public boolean equals(Object obj) {
            Person p = (Person) obj;
            if (this.name==p.name){
                return true;
            }else {
                return false;
            }
        }
    }
    
    //测试类
    public class Test01 {
          
          
        public static void main(String[] args) {
          
          
            Person p1 = new Person("小明",18);
            System.out.println(p1);
            System.out.println(p1.toString());
    
            Person p2 = new Person("小红",20);
            System.out.println(p1==p2);
            System.out.println(p1.equals(p2));
    
            Person p3 = p1;
            System.out.println(p1==p3);
            System.out.println(p1.equals(p3));
        }
    }
    

15. 接口

  • 接口 : java语言中一种引用类型,是方法的集合,主要是封装方法,它与定义类的方式相似 interface关键字,他也会被编译成class文件,但一定要明确它不是类,是另外一种数据类型(数组,类,接口)

  • Java里的接口, 就是抽象方法常量值的集合(简单理解为接口就是一种特殊的抽象类)

    [修饰符] interface 接口名 {
          
          
        //静态常量
        //抽象方法
        //默认方法
        //静态方法
        //私有方法
    }
    
  • 实现接口

    • 接口的使用,他不能创建对象,但是可以被实现( implements , 类似于被继承)
    • 类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类,实现的动作类似于继承,格式相似,只是关键字不同,实现用的是implements关键字
    [修饰符] class 实现类 implements 接口 {
          
          
        //重写接口中的抽象方法[必须],如果实现类是抽象类,name可以不重写
        //重写接口中默认方法[可选]
    }
    
    [修饰符] class 实现类 extends 父类 implements 接口 {
          
          
        //重写接口中的抽象方法[必须],如果实现类是抽象类,name可以不重写
        //重写接口中默认方法[可选]
    }
    
  • 非抽象类实现接口

    • 必须重写接口所有的抽象方法
    • 继承了接口的默认方法,即可以直接调用,也可以重写
      • 重写时,default关键字就不要再写了,它只用于接口中表示默认方法,到类中就没有默认方法这个概念了
      • 不能重写静态方法
    //练习
    //声明一个接口LiveAble
    	//包含两个抽象方法 void eat();void breathe();
    	//包含一个默认方法default void sleep(); 睡觉
    	//包含静态方法 static void drink(); 喝水
    package com.kgc04;
    public interface LiveAble {
          
          
      public abstract void eat();
        public abstract void breathe();
    
        public default void sleep(){
          
          
            System.out.println("不动");
        }
        public static void drink(){
          
          
            System.out.println("喝水");
        }
    }
    
    package com.kgc04;
    public class Animal implements LiveAble{
          
          
        @Override
        public void eat() {
          
          
            System.out.println("吃东西");
        }
        @Override
        public void breathe() {
          
          
            System.out.println("吸入氧气,呼出二氧化碳");
        }
        @Override
        public void sleep() {
          
          
            System.out.println("闭上眼睡觉");
        }
    }
    
    package com.kgc04;
    public class Plant implements LiveAble{
          
          
        @Override
        public void eat() {
          
          
            System.out.println("吸收营养");
        }
    
        @Override
        public void breathe() {
          
          
            System.out.println("吸入二氧化碳,呼出氧气");
        }
    }
    
    package com.kgc04;
    public class Test {
          
          
        public static void main(String[] args) {
          
          
            //创建实现类(子类) 对象
            Animal a = new Animal();
            a.eat();
            a.sleep();
            a.breathe();
            System.out.println("------------------------");
            //创建实现类 对象
            Plant p = new Plant();
            p.eat();
            p.sleep();
            p.breathe();
            System.out.println("------------------------");
            //通过接口名,调用静态方法
            LiveAble.drink();
        }
    }
    

16. 异常

  • 异常 : 指的是程序在执行过程中,出现的非正常的情况,如果不处理最终会导致JVM的非正常停止

  • 对于异常有两种解决方法,一种是遇到错误就终止程序的运行,另一种是由程序员在编写程序时就考虑到错误的检测,错误消息的提示,以及错误的处理

  • 异常的根类 : java.lang.Throwable,其子下有两个子类,java.lang.Error与java.lang.Exception,平时所说的异常指的是java.lang.Exception

    • Error : 严重错误,好比绝症
    • Excpetion : 表示异常,变成错误或偶然的外在因素导致的一般性问题,程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的,好比感冒
      • 下标越界,读的文件不存在等
  • Throwable 中常用的方法

    • public void printStatckTrace() : 打印异常的详细信息,包含异常的类型,异常的原因,出现的位置
    • public void getMessage() : 获取发生异常的原因,提示错误原因
  • Exception 异常的分类

    • 编译时异常 : checked 异常,在编译时检查,如果没有处理异常则编译失败
    • 运行时异常 : runtime 异常,在运行期间,检查异常,如下标越界,类型转换
  • java异常处理的5个关键字 : try catch finally , throw throws

    • try…catch 捕获异常

      • 是对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理
      try{
              
              
          //可能出现异常的代码
      }catch(异常类型 e){
              
              
          //处理异常的代码
          //记录日志/打印异常信息/继续抛出异常
      }
      
      //例1
      package com.kgc01;
      import java.io.File;
      import java.io.FileNotFoundException;
      
      public class TestException {
              
              
          public static void main(String[] args) {
              
              
              File f = new File("d:\\a.txt");
              try{
              
              
                  if (!f.exists()){
              
              
                      throw new FileNotFoundException("d:\\a.txt"+"不存在");
                  }
              }catch (FileNotFoundException e){
              
              
                  System.out.println(e.getMessage());
              }
          }
      }
      
      //例2
      package com.kgc01;
      public class Test01 {
              
              
          public static void main(String[] args) {
              
              
              int[] arr = new int[2];
              //下标越界
              try{
              
              
                  for (int i = 0; i <=arr.length ; i++) {
              
              
                      System.out.println(arr[i]);
                  }
              }catch (ArrayIndexOutOfBoundsException e){
              
              
                  System.out.println(e);//出现错误的下标
                  System.out.println(e.getStackTrace());//错误地址
              }
          }
      }
      
      //例3
      package com.kgc01;
      import java.util.Scanner;
      
      public class Test02 {
              
              
          public static void main(String[] args) {
              
              
              Scanner sc = new Scanner(System.in);
              System.out.print("请输入一个整数:");
              //将可能出现错误的地方try起来(输入字符串)
              try{
              
              
                  int a = sc.nextInt();
                  System.out.println(a);
              }catch(Exception e){
              
              
                  //捕获输出错误类型
                  System.out.println(e);
              }
              //不影响程序的运行
              System.out.println("正常运行");
          }
      }
      //注:Exception是所有错误的父类,不知道错误类型可以使用Exception
      
  • throws 抛出异常,交给上级处理,如果都不处理,最终会交给JVM

    • package com.kgc01;
      
      import java.util.InputMismatchException;
      import java.util.Scanner;
      
      public class Test03 {
              
              
          public static void main(String[] args) {
              
              
              try{
              
              
                  getInt();
              }catch (ArrayIndexOutOfBoundsException e){
              
              
                  System.out.println("请输入一个整数");
              }
          }
          public static void getInt() throws InputMismatchException{
              
              
              Scanner sc = new Scanner(System.in);
              System.out.print("请输入一个整数:");
              int a = sc.nextInt();
              System.out.println(a);
              System.out.println("正常运行");
          }
      }
      
  • finally

    • 有一些特定的代码,不论是否出现异常,都要执行的代码

      try{
              
              
          //代码
      }catch(){
              
              
          //代码
      }finally{
              
              
          //代码
      }
      
      package com.kgc01;
      
      import java.util.InputMismatchException;
      import java.util.Scanner;
      
      public class Test03 {
              
              
          public static void main(String[] args) {
              
              
              try{
              
              
                  getInt();
              }catch (InputMismatchException e){
              
              
                  System.out.println("请输入一个整数");
              }finally {
              
              
                  System.out.println("欢迎下次光临");
              }
          }
          public static void getInt() throws InputMismatchException{
              
              
              Scanner sc = new Scanner(System.in);
              System.out.print("请输入一个整数:");
              int a = sc.nextInt();
              System.out.println(a);
              System.out.println("正常运行");
          }
      }
      
  • 异常处理

    • 一次性处理
      • catch后写所有异常的父类 Exception
    • 分开处理
      • 多个catch,各自处理各自的异常
    • 不处理
      • throws抛出异常,交给上级处理

17. QuickHit

需求概述:
根据输入速率和正确率将玩家分为不同级别
级别越高,一次显示的字符数越多,玩家正确输入一次的得分也越高
规定时间内完成规定次数的输入,正确率达到规定要求,则升级
玩家最高级别为6级、初始级别一律为1级
用户错误输入一次,游戏结束

核心代码

package com.kgc;
//生成随机的字符串
import java.util.Random;
import java.util.Scanner;

public class QuickHit {
    
    
    public static void main(String[] args) {
    
    
        //创建random随机对象
        Random random = new Random();
        //可改变长度的字符串
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < 1; i++) {
    
               //控制字符串的长度
            //产生一个随机数
            int rand = random.nextInt(4);//控制字符串的难易程度
            //根据随机数拼接字符串
            switch (rand){
    
    
                case 0:
                    buffer.append(">");
                    break;
                case 1:
                    buffer.append("<");
                    break;
                case 2:
                    buffer.append("*");
                    break;
                case 3:
                    buffer.append("&");
                    break;
            }
            System.out.println("buffer="+buffer);
            Scanner sc = new Scanner(System.in);
            System.out.print("请输入:");
            //输入前开始计时(从19700101 00:00:00开始)
            long l1 = System.currentTimeMillis();
            String in = sc.next();
            //输入后结束计时
            long l2 = System.currentTimeMillis();
            //打印时间差
            long l = (l2-l1)/1000;
            System.out.println("所用时长"+l+"秒");
            if (in.equals(buffer.toString())){
    
    
                System.out.println("相同");
            }else {
    
    
                System.out.println("不相同");
            }
        }
    }
}

游戏项目

  • 测试类
    • 创建一个玩家
    • 调用play方法
public class Test {
    
    
    public static void main(String[] args) {
    
    
        //创建一个玩家
        Player player = new Player();
        player.play();
        
    }
}
  • 玩家级别类
    • 属性 : 级别编号,各级别一次输出字符串的长度,各级别输出字符串的次数,各级别闯关的时间限制,各级别成功输入一次字符串之后增加的分值
    • 构造方法(全参),get/set
public class Leavel {
    
    
    private int leavelNo;//级别号
    private int strLength;//各级别一次输出字符串的长度
    private int strTimes;//各级别输入字符串的次数
    private int timeLimit;//各级别闯关的时间限制
    private int perScore;//各级别成功输入一次的字符串后增加的分值

    public Leavel(int leavelNo, int strLength, int strTimes, int timeLimit, int perScore) {
    
    
        this.leavelNo = leavelNo;
        this.strLength = strLength;
        this.strTimes = strTimes;
        this.timeLimit = timeLimit;
        this.perScore = perScore;
    }

    public int getLeavelNo() {
    
    
        return leavelNo;
    }

    public void setLeavelNo(int leavelNo) {
    
    
        this.leavelNo = leavelNo;
    }

    public int getStrLength() {
    
    
        return strLength;
    }

    public void setStrLength(int strLength) {
    
    
        this.strLength = strLength;
    }

    public int getStrTimes() {
    
    
        return strTimes;
    }

    public void setStrTimes(int strTimes) {
    
    
        this.strTimes = strTimes;
    }

    public int getTimeLimit() {
    
    
        return timeLimit;
    }

    public void setTimeLimit(int timeLimit) {
    
    
        this.timeLimit = timeLimit;
    }

    public int getPerScore() {
    
    
        return perScore;
    }

    public void setPerScore(int perScore) {
    
    
        this.perScore = perScore;
    }
}
  • 配置级别类
    • 不可更改的,静态的,定义一个级别的数组,数组的长度是6
    • 配置没有人调用,所以需要放到静态代码块里
public class LevelParam {
    
    
    public final static Level[] levels = new Level[6];  //对应6个级别,不可修改的,加载类时同时加载
    static {
    
    
        levels[0] = new Level(1,1,6,30,1);
        levels[1] = new Level(2,2,5,25,2);
        levels[2] = new Level(3,3,4,20,3);
        levels[3] = new Level(4,4,3,15,5);
        levels[4] = new Level(5,5,2,10,8);
        levels[5] = new Level(6,6,1,5,20);
    }
}
  • 玩家类
    • 属性 级别号,当前积分,级别的开始时间,级别的使用时间
import java.util.Scanner;
public class Player {
    
    
    private int levelNo;//级别
    private int curScore;//当前积分
    private long startTime=0;//各级别开始时间
    private int usedTime;//各级别已经用的时间

    public int getLevelNo() {
    
    
        return levelNo;
    }

    public long getStartTime() {
    
    
        return startTime;
    }

    public void setStartTime(long startTime) {
    
    
        this.startTime = startTime;
    }

    public void setLevelNo(int levelNo) {
    
    
        this.levelNo = levelNo;
    }

    public int getCurScore() {
    
    
        return curScore;
    }

    public void setCurScore(int curScore) {
    
    
        this.curScore = curScore;
    }

    public int getUsedTime() {
    
    
        return usedTime;
    }

    public void setUsedTime(int usedTime) {
    
    
        this.usedTime = usedTime;
    }

    public void play(){
    
    
        Game game = new Game(this);
        Scanner sc = new Scanner(System.in);
        //外层 循环控制级别
        for (int i = 0; i < LevelParam.levels.length; i++) {
    
    
            //1.晋级
            levelNo+=1;
            //2.晋级后计时清零,积分清零
            startTime = System.currentTimeMillis();
            curScore=0;
            //内层 循环控制循环次数
            //3.控制一个级别玩的次数
            for (int j = 0; j < LevelParam.levels[levelNo-1].getStrTimes(); j++) {
    
    
                //3.1 游戏输出字符串
                String outStr = game.printStr();
                //3.2 接收用户输入
                String inStr = sc.next();
                //3.3 游戏中判断玩家输入的是否正确并输出相应的结果信息
                game.printResult(outStr,inStr);
            }
        }
    }

}
  • 游戏类
    • 属性 : 玩家
    • 构造方法
    • printStr() 打印随机字符串的结果并返回,printResult(输出的结果,用户输入的字符串) 打印结果信息
import java.util.Random;

//游戏类
public class Game {
    
    
    public Player player;
    //构造方法,传入玩家
    public Game(Player player) {
    
    
        this.player = player;
    }
    //输出指定级别,规定长度的字符串
    public String printStr(){
    
    
        int strLength = LevelParam.levels[player.getLevelNo()-1].getStrLength();  //取到对应玩家的长度
        StringBuffer buffer = new StringBuffer();
        Random random = new Random();
        //通过循环生成 要输出的字符串
        //外循环控制字符串的长度
        for (int i = 0; i < strLength; i++) {
    
    
            //产生随机数
            int rand = random.nextInt(strLength);
            //根据随机数拼接字符串
            switch(rand){
    
    
                case 0:
                    buffer.append(">");
                    break;
                case 1:
                    buffer.append("<");
                    break;
                case 2:
                    buffer.append("*");
                    break;
                case 3:
                    buffer.append("&");
                    break;
                case 4:
                    buffer.append("%");
                    break;
                case 5:
                    buffer.append("#");
                    break;
            }
        }
        //输出字符串
        System.out.println(buffer);
        //返回字符串
        return buffer.toString();
    }
    //判断玩家输入是否正确,并输出相应的结果信息
    public void printResult(String out,String in){
    
    
        //判断是否输入正确
        boolean flag;
        if(out.equals(in)){
    
    
            flag=true;
        }else {
    
    
            flag=false;
        }
        //如果输入正确
        if (flag){
    
    
            long currenttime=System.currentTimeMillis();  //获取当前时间的毫秒
            // 判断是否超时
            // 已用时
            long yys=(currenttime-player.getStartTime())/1000;
            //System.out.println(yys);
            // 级别时间
            long jbsj=LevelParam.levels[player.getLevelNo()-1].getTimeLimit();
            if (yys>jbsj) {
    
    
                System.out.println("太慢了");
                System.exit(1);  // 系统退出
            }else{
    
    //如果没有超时
                //取出之前的积分+过一次给的分数
                int jf = player.getCurScore()+LevelParam.levels[player.getLevelNo()-1].getPerScore();
                //计算积分
                player.setCurScore(jf);
                //计算已用时
                player.setUsedTime((int)yys);
                System.out.println("输入正确,您的级别是:"+player.getLevelNo()+"\t"+"您的积分是:"+player.getCurScore()+"\t"+"已用时间:"+player.getUsedTime());
                //判断用户是否已经闯关到最后一关
                if(player.getLevelNo()==6){
    
    
                    //取出当前积分和,最后一关玩的次数*每次的分数,如果相等就通关了
                    int dqjf= player.getCurScore();
                    int tgf = LevelParam.levels[player.getLevelNo()-1].getStrTimes()*LevelParam.levels[player.getLevelNo()-1].getPerScore();
                    if (dqjf==tgf){
    
    
                        System.out.println("恭喜通关!");
                        System.exit(0);
                    }
                }
            }
        }
        else {
    
    
            System.out.println("错误,退出");
            System.exit(1);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Su_mer/article/details/127875593