zoukankan      html  css  js  c++  java
  • Java基础(九)

    综合案例

        此前我们已经练习了根据集合当中的字符串对象读写文件,而本综合案例主要练习根据集合当中的自定义对象来读写文件。

    场景介绍

        很多网络游戏当中都有组队模式,例如魔兽世界、DotA、英雄联盟(LOL)、王者荣耀等,均为5人组队进行游戏。即使在现实生活中,打麻将、斗地主也都是多人进行的游戏。那么对于多人组队的游戏,典型的场景为:

        1.有5个人都在玩游戏;

        2.这5个人组成一个队伍;

        3.这支队伍进行游戏;

        4.队伍成员彼此欣赏,决定以后还要组队一起玩;

        5.一段时间后大家再次组队游戏。

    分析整体思路

         

    实现

      框架代码

    //自定义一个类,代表英雄
    
    public class Hero {
    
        //成员变量
    
        private String name;   //名字
    
        private int attack;    //英雄的攻击力
    
        private String type;   //英雄的类型
    
       
    
        public Hero() {
    
        }
    
       
    
        public Hero(String name, int attack, String type) {
    
            this.name = name;
    
            this.attack = attack;
    
            this.type = type;
    
        }
    
       
    
        public String getName() {
    
            return name;
    
        }
    
        public void setName(String name) {
    
            this.name = name;
    
        }
    
        public int getAttack() {
    
            return attack;
    
        }
    
        public void setAttack(int attack) {
    
            this.attack = attack;
    
        }
    
        public String getType() {
    
            return type;
    
        }
    
        public void setType(String type) {
    
            this.type = type;
    
        }
    
    }
    //测试类
    
    public class Test {
    
        public static void main(String[] args) {
    
            //1.首先创建一个集合,用来存储五个英雄
    
            ArrayList<Hero> list = new ArrayList<>();
    
           
    
            //2.读文件,把数据加到集合当中.
    
            System.out.println("加载文件的数据到集合当中.");
    
            //list.add(new Hero());    //假设已经从文件当中加载得到了数据,并且加入集合当中
    
           
    
            //3.判断一下集合当中有没有内容,是不是新的?
    
            boolean isNew = list.size() == 0; //如果集合的长度为0,说明这是新的队伍
    
            System.out.println("这是不是新队伍:" +isNew);
    
           
    
            //如果是新的队伍,没有人,就需要创建五个对像加入到集合当中
    
            if(isNew) {
    
                System.out.println("创建5个对象加入集合中.");
    
            }
    
            //如果不是新的队伍,已经有人了,就不需要创建了.
    
           
    
            System.out.println("我们队伍的阵容是:");
    
            //遍历集合,输出其中的每一个对象的具体信息
    
            System.out.println("循环5次进行遍历");
    
           
    
           
    
            //统计一下总和战斗力是多少.
    
            int totalAttack = 0;   //稍后在计算
    
            System.out.println("我们队伍的总战斗力是:" + totalAttack);
    
           
    
            //判断一下集合是不是新的
    
            if(isNew) {
    
                System.out.println("将集合的数据写到文件中.");
    
            }
    
            //如果集合不是新的,而是从文件中加载得到的数据,就什么都不用做
    
            System.out.println("退出游戏");
    
        }
    
    }

    英雄问世(创建对象)

      在测试类mian方法外添加方法

    /*
    
         * 定义一个方法,用来向集合当中添加五位英雄.三要素: 返回值类型: 参数集合是引用类型,形式参数的操作会影响实际参数,所以不需要返回值,void 方法名称:
    
         * addFiveHeros 参数列表: ArrayList<Hero>
    
         */
    
        public static void addFiveHeros(ArrayList<Hero> list) {
    
            // 英雄信息来自于键盘输入(Scanner)
    
            Scanner sc = new Scanner(System.in); // 创建一个Scanner用来进行键盘输入
    
     
    
            for (int i = 1; i <= 5; i++) { //循环5次
    
                //键盘输入英雄的三个信息
    
                System.out.println("请输入第" + i + "英雄的名字:");
    
                String name = sc.next();   //获取字符串
    
                System.out.println("请输入第" + i + "英雄的攻击力:");
    
                int attack = sc.nextInt(); //获取int数字
    
                System.out.println("请输入第" + i + "英雄的类型:");
    
                String type = sc.next();
    
               
    
                Hero hero = new Hero(name,attack,type);   //创建一个英雄对象
    
                list.add(hero);    //把英雄对象添加到集合当中
    
            }
    
        }

    main方法对应的地方调用方法进行添加

        

        // 如果是新的队伍,没有人,就需要创建五个对像加入到集合当中
    
            if (isNew) {
    
                //调用方法,向集合当中添加五个英雄
    
                addFiveHeros(list);
    
            }

    阵容展示(遍历集合)

           在测试类mian方法外添加遍历方法

          

     /*
    
         * 定义一个方法,用来遍历集合当中所有对象的信息,三要素:
    
         * 返回值类型:只是进行打印输出而已,所以使用void
    
         * 方法名称:showHeros
    
         * 参数列表:ArrayList<Hero>
    
         */
    
        public static void showHeros(ArrayList<Hero> list) {
    
            for (int i = 0; i < list.size(); i++) {
    
                Hero hero = list.get(i);   //当前英雄
    
                System.out.println("英雄名字: " + hero.getName() + ",攻击力:" + hero.getAttack() + ",类型:" + hero.getType());
    
            }
    
        }

    mian方法中调用相应的方法进行遍历

      

        System.out.println("我们队伍的阵容是:");
    
            // 遍历集合,输出其中的每一个对象的具体信息
    
            showHeros(list);

    战力计算(对象成员变量求和)

           在测试类mian方法外添加计算方法

    /*
    
         * 定义一个方法,用来根据集合求出战斗力总值.三要素:
    
         * 返回值类型:int,代表结果总和
    
         * 方法名称:getTotalAttack
    
         * 参数列表:ArrayList<Hero>
    
         */
    
        public static int getTotalAttack(ArrayList<Hero> list) {
    
            int total = 0; //代表总攻击力
    
            for (int i = 0; i < list.size(); i++) {
    
                Hero hero = list.get(i);
    
                //将每个英雄的战斗力全都累加到total当中
    
                total += hero.getAttack();
    
            }
    
            return total;
    
        }

    mian方法中调用相应的方法进行计算

        // 统计一下总和战斗力是多少.
      
            int totalAttack = getTotalAttack(list);   //根据集合的内容求出总攻击力
    
            System.out.println("我们队伍的总战斗力是:" + totalAttack);

    桃园结义(写文件)

      在测试类main方法外添加写入文件数据方法

    /*
    
         * 定义一个方法,用来将集合当中的对象数据全部都写到文件里.三要素:
    
         * 返回值类型:void
    
         * 方法名称:saveToFile
    
         * 参数列表:ArrayList<Hero>
    
         */
    
        public static void saveToFile(ArrayList<Hero> list) throws IOException {
    
            BufferedWriter bw = new BufferedWriter(new FileWriter("friends.txt"));
    
           
    
            //遍历集合,一个对象一个对象地挨个儿写
    
            for (int i = 0; i < list.size(); i++) {
    
                Hero hero = list.get(i);   //当前英雄
    
                //需要将一个Hero对象转换成为字符串,将三个成员变量拼接成为一个字符串
    
                //后羿,200,射手
    
                //宫本武藏,1400,刺客
    
                //机器人300,500,辅助
    
                String  str =  hero.getName()+","+hero.getAttack()+","+hero.getType();
    
                //将对应的字符串写道文件中
    
                bw.write(str);
    
                bw.newLine();  //不要忘记把每个属性换行
    
            }
    
            bw.close();    //最后别忘记关闭流
    
        }

    mian方法中调用相应的方法进行写文件

        // 判断一下集合是不是新的
    
            if (isNew) {
    
                saveToFile(list);  //调用方法将集合的信息写到文件中.报错记得抛异常
    
            }

    再度相约(读文件)

      扩展知识:

        如何才能将一个字符串"100"转换成为Int数字100?

      格式:

        Integer.parseInt(String str);

        参数是字符串,返回值是int数字,可以将字符串转换成为int数字.

        但是有前提:这个参数字符串必须只含有数字,格式必须是int数字!

    在测试类main方法外添加读取文件数据方法

    /*
    
         * 定义一个方法,用来读取文件,将数据添加到集合当中.三要素:
    
         * 返回值类型:参数集合是引用类型,形式参数的操作会影响实际参数,所以void
    
         * 方法名称:loadFileToList
    
         * 参数列表:ArrayList<Hero>
    
         */
    
        public static void loadFileToList(ArrayList<Hero> list) throws NumberFormatException, IOException {
    
            BufferedReader br = new BufferedReader(new FileReader("friends.txt"));
    
           
    
            String line;   //代表一行字符串
    
            while((line = br.readLine()) != null){
    
                //需要将字符串转换成为一个Hero对象
    
                //首先将一个完整的字符串切分成为若干小段儿
    
                String[] array = line.split(",");
    
                String name = array[0];        //姓名
    
               
    
                //将字符串转换成为对应的int基本类型数字
    
                int attack = Integer.parseInt(array[1]);   //攻击力
    
                String type = array[2];        //类型
    
               
    
                //根据三条信息创建一个英雄对象
    
                Hero hero = new Hero(name,attack,type);  
    
                list.add(hero);    //将对象添加到集合当中
    
            }
    
            br.close();    //不要忘记关闭流
    
        }

    mian方法中调用相应的方法进行读文件

        // 2.读文件,把数据加到集合当中.
    
            loadFileToList(list);

    接口

      现实生活的接口举例

        

    面向对象的接口思想

         

    使用接口的好处

         

    格式与组成部分

      

    //接口的基本定义格式:
    public interface 接口名称 {
        //...
    }

      接口当中可以包含的组成部分有:

    1. 抽象方法[今天学习的重点所在]
    2. 常量
    3. 默认方法(java 8)
    4. 静态方法(java 8)
    5. 私有方法(java 9)

    抽象方法定义

        

    /*
    
     * 如何定义一个抽象方法:  
    
     *      public abstract 返回值类型 方法名称(参数类型 参数名称);
    
     * 注意:
    
     *      1.接口中的抽象方法,修饰如果写必须是:public abstract
    
     *      2.接口中的抽象方法,修饰符可以省略不写,默认是:public abstract
    
     *      3.抽象方法只有方法头,不能有方法体大括号.
    
     */
    
    public interface Animal {
    
        //定义了一个抽象方法,吃东西
    
        public abstract void eat();
    
       
    
        //定义了另一个抽象方法:睡觉
    
        //省略了public abstract也照样是抽象方法
    
        /*public abstract*/ void sleep();
    
    }

      

    实现类的定义

    /*
     * 如果想要使用定义好的接口,必须有一个接口的"实现类".
     * 定义实现类格式为:
     * 
     * public class 实现类名称 implements 接口名称 {
     *         //一定要覆盖重写所有的抽象方法
     * }
     * 什么是覆盖重写(Override)抽象方法?
     * 1.将接口当中的抽象方法抄写过来
     * 2.去掉abstract关键字
     * 3.写上大括号方法体
     * 
     * Cat就是Animal接口的实现类,Cat类实现了Animal接口.
     */
    public class Cat implements Animal {
        public void eat() {
            System.out.println("猫吃鱼");
        }
        public void sleep() {
            System.out.println("猫睡觉");
        }
    }

    与实现类的基本使用

      

    如何使用接口与实现类?
     * 
     * 创建:
     * 接口名称 引用名 = new 实现类名称();
     * 
     * 调用:
     * 引用名.抽象方法名(参数);
     * 
     * 注意:
     * 1.左边是接口类型,那么只能调用接口当中定义好的内容,不能调用右侧实现类当中特有的内容.(接口隔离)
     * 2.当调用接口当中的抽象方法时,真正进行运行的是右侧new的时候类的具体方法内容.
     * 总结:调用的时候看左边,运行的时候看右边.
     */
    
    
    //实现类添加特有的方法:
    public class Cat implements Animal {
        //省略吃睡两个方法;
        
        //这是一个Cat自己特有的方法,接口当中并没有定义
        public void catchMouse() {
            System.out.println("猫抓老鼠");
        }
    }
    
    //接口调用特有方法 错误!
    public class Demo01Interface {
        public static void main(String[] args) {
            //创建:
            Animal cat = new Cat();
            
            //省略调用吃睡两个方法
            
            //cat.catchMouse();    //错误!无法调用右侧实现类专有的方法,只能调用接口的方法.
        }
    }

    面向接口编程

     

    //添加一个狗类
    public class Dog implements Animal{
        public void eat() {
            System.out.println("狗吃骨头");
        }
        public void sleep() {
            System.out.println("狗睡觉");
        }
        
        //特有方法
        public void watchHouse() {
            System.out.println("狗看家");
        }
    }
    
    /*
     * 使用接口作为左侧类型的好处所在:
     * 屏蔽掉了右侧的个性特有的内容,达到隔离,统一的目的.
     * 
     * 面向接口编程:
     * 如果使用的功能,接口已经可以满足,那么就不在乎具体的类是谁,只在乎接口即可.
     */
    public class Demo02Interface {
        public static void main(String[] args) {
            Cat cat = new Cat(); // 创建了一只猫
            method(cat); // 将猫对象传递给方法,间接使用其中的eat和sleep方法.
    
            Dog dog = new Dog(); // 创建了一只狗
            method(dog);
    
        }
    
        // 使用接口作为参数类型,这样就不区分到底是猫还是狗.
        public static void method(Animal animal) {
            animal.eat();
            animal.sleep();
    //        animal.watchHouse();    //错误!无法调用狗的专有的方法
    //        animal.catchMouse();    //错误!无法调用猫的专有的方法
        }
    }

    不必要的接口实现类

    //定义一个计算器的接口
    public interface Calculator {
        public abstract int sum(int a,int b);
    }
    
    //计算器接口的实现类
    public class CalculatorImpl implements Calculator{
        public int sum(int a,int b) {
            int result = a + b;
            return result;
        }
    }
    
    public class Demo01Calc {
        public static void main(String[] args) {
            //首先使用接口的格式来创建了一个计算器对象
            Calculator calculator = new CalculatorImpl();
            
            //将计算器对象交给method方法去使用
            method(calculator);
        }
        
        //参数是接口类型,计算器接口
        public static void method(Calculator calculator) {
            int result = calculator.sum(10, 20);
            System.out.println("结果是:"+result);
        }
    }

    Lambda表达式

      体验Lambda表达式(新世界大门)

      

    //定义一个计算器的接口
    
    public interface Calculator {
    
        public abstract int sum(int a,int b);
    
    }
    
     
    
    //Lambda 函数式
    
    public class Demo01Calc {
    
        public static void main(String[] args) {
    
           
    
            //将计算器对象交给函数式 method方法去使用
    
            method((a,b) -> a + b);
    
        }
    
       
    
        //参数是接口类型,计算器接口
    
        public static void method(Calculator calculator) {
    
            int result = calculator.sum(100, 200);
    
            System.out.println("结果是:"+result);
    
        }
    
    }

    理解Lambda的语义

    //Lambda 函数式
    
    public class Demo01CalcLambda {
    
        public static void main(String[] args) {
    
            method((a,b) -> a + b);
    
            //Lambda表达式:(a,b) -> a + b
    
            //method方法需要一个Calculator接口类型的参数
    
            //Lambda表达式就是充当了Calculator接口类型的参数
    
            //初步理解:
    
            //1.Lambda表达式前面的小括号,其实就是接口抽象方法的小括号.
    
            //2.箭头代表拿着小括号的数据做什么事情,是一个指向的动作.
    
            //3.箭头后面就代表拿到了参数之后做什么事情.
    
            //Lambda表达式的语义本身就代表了怎么做这件事情,没有对象的概念在里面.(更加简单直观.)
    
        }
    
        //参数是接口类型,计算器接口
    
        public static void method(Calculator calculator) {
    
            int result = calculator.sum(100, 200);
    
            System.out.println("结果是:"+result);
    
        }
    
    }

    函数式接口

    /*
    
     * Java当中使用Lambda表达式的前提是:必须有"函数式接口".
    
     *
    
     * 概念:有且仅有一个抽象方法的接口,叫做函数式接口.
    
     * 可以同时有其它:默认方法、静态方法.....但不能再有抽象方法了
    
     *
    
     * 如何才能万无一失地检测一下当前接口是不是函数式接口呢?
    
     * 用一个固定的格式写在public interface之前一行即可:
    
     * @FunctionalInterface
    
     * public interface 函数式接口名{
    
     *      //...
    
     *}
    
     */
    
    @FunctionalInterface
    
    public interface Calculator {
    
        public abstract int sum(int a,int b);
    
    }

    标准格式

    /*
    
     * Lambda表达式要想使用,一定要有函数式接口的推断环境。
    
     * 1.要么通过方法的参数类型来确定是哪个函数式接口
    
     * 2.要么通过赋值操作来确定是哪个函数式接口
    
     * Lambda的格式就是为了将抽象方法,翻译成为以下三点:
    
     * 1.一些参数(方法参数)
    
     * 2.一个箭头
    
     * 3.一些代码(方法体,大括号)
    
     * 例如抽象方法:
    
     * public abstract int sum(int a,int b);
    
     * 翻译成为Lambda的标准格式:
    
     * (int a,int b) -> { return a + b;}
    
     */
    
    public class Demo03Lambda {
    
        public static void main(String[] args) {
    
            method( (int a,int b) -> { return a + b;} );
    
        }
    
       
    
        public static void method(Calculator calculator) {
    
            int result = calculator.sum(100, 200);
    
            System.out.println("结果是:"+result);
    
        }
    
    }

    上下文推断

    public class Demo03Lambda {
    
        public static void main(String[] args) {
    
            //调用方法的时候,参数类型是函数式接口,所以Lambda可以推断出来是哪个接口
    
            method( (int a,int b) -> { return a + b;} );
    
            System.out.println("============================");
    
           
    
            //也可以根据赋值语句左侧的类型来进行Lambda上下文推断
    
            Calculator param = (int a,int b) -> { return a + b ; };
    
            method(param);
    
           
    
    //      (int a,int b) -> { return a + b ; };  //错误写法! 没有上下文环境,Lambda就无法推断是哪个函数式接口
    
        }
    
       
    
        public static void method(Calculator calculator) {
    
            int result = calculator.sum(100, 200);
    
            System.out.println("结果是:"+result);
    
        }
    
    }

    简便格式

    //注意!不管写不写@FunctionalInterface,只要是有且仅有一个抽象方法的接口,就是函数式接口!
    
    @FunctionalInterface
    
    public interface MyInter {
    
        //作用:将参数++,然后返回结果
    
        public abstract int singlePlus(int num);
    
    }
    
     
    
    /*
    
     * 在Lambda表达式当中,凡是可以推导的,都是可以省略的.
    
     * 1.Lambda表达式当中的参数类型可以省略不写.
    
     * 2.如果参数有且只有一个,那么小括号可以省略.
    
     * 3.如果语句只有一个,那么大括号和return也可以省略.
    
     */
    
    public class DemoLambdaSimple {
    
        public static void main(String[] args) {
    
           //标准格式:
    
           method( (int x) -> { return ++x; } );
    
          
    
           //省略参数类型:
    
           method( (x) -> { return ++x; } );
    
          
    
           //省略参数小括号:
    
           method( x -> { return ++x; } );
    
          
    
           //省略大括号和return关键字:
    
           method( x -> ++x );
    
        }
    
        public static void method(MyInter inter) {
    
           int result = inter.singlePlus(10);
    
           System.out.println("结果:" + result);
    
        }
    
    }

    知识总结

      1.使用接口的好处:通用性、隔离性。

      2.定义接口的格式:

        

        public interface接口名{
    
         //...
    
        }

      3.接口的组成部分:

        a)抽象方法【核心内容】

        b)常量

        c)默认方法(Java8)

        d)静态方法(Java8)

        e)私有方法(Java9)

      4.定义一个抽象方法,格式:

        public abstract 返回值类型 方法名(参数类型参数名);

        a)修饰符 public abstract也可以省略不写

        b)抽象方法不可以写方法体大括号

      5.接口要想使用,一定要有一个实现类。如何实现?

      

    public class类名称implements接口名{
        //覆盖重写所有的抽象方法
    
    }

      6.如何覆盖重写(Override)抽象方法呢?一般步骤:

        a)将抽象方法抄写过来

        b)去掉abstract关键字

        c)写上方法体

      7.使用接口和实现类的一般格式:

        a)创建:接口名称 引用名 = new实现类名称();

        b)调用:引用名.抽象方法名(参数);

        c)注意:

          i. 只能调用左侧接口当中定义好的方法,无法调用右侧类当中特有的方法。

          ii. 运行程序的时候,方法的执行者其实是右边的类对象。

          iii. "调用的时候看左边,但是运行的时候看右边”。

      8.从Java8开始,没有接口的实现类,也可以直接使用接口:Lambda表达式。Lambda表达式就替代了实现类。

      9.Lambda使用前提:一定要有函数式接口才能用,没有函数式接口就不能用Lambda表达式。

      10.函数式接口:有且仅有一个抽象方法的接口。无所谓有没有@FunctionalInterface,这是一个可选的检测手段而已。

      11.使用Lambda必须有推断环境:

        a)要么根据参数类型传参来推断函数式接口。

        b)要么就根据赋值语句左侧类型来推断函数式接口。

      12.Lambda表达式的标准格式:(int a,int b) -> { return a+b; }

        a) 一些参数(方法的参数)

        b)一个箭头

        c)一些代码(方法体)

      13.Lambda表达式的简便格式:

        (int num) -> { return ++num; }

        (num) -> { return ++num; }

        num -> { return ++num; }

        num -> ++num;

        a)参数的类型可以省略。

        b) 如果有且仅有一个参数,那么小括号可以省略

        c)如果有且仅有一个语句,那么大括号和return也可以省略

  • 相关阅读:
    京东POP2020新店新规
    hdu 1203
    hdu 1513
    有关Canvas的一点小事—canvas数据和像素点
    有关Canvas的一点小事—图像绘制
    有关Canvas的一点小事--鼠标绘图
    Javascript和jquery事件--键盘事件KeyboardEvent
    [转]DOM0,DOM2,DOM3事件处理方式区别
    Javascript和jquery事件--鼠标事件的小结
    Javascript和jquery事件--鼠标移动事件mousemove
  • 原文地址:https://www.cnblogs.com/loveyoul9/p/11483362.html
Copyright © 2011-2022 走看看