面向对象程序设计知识点汇总

    科技2026-08-12  15

    本博客主要包含面向对象程序设计中的知识点,针对面向对象程序设计这门课程进行知识点的总结,如有疑问或不懂的地方,亦或是知识点有不对的地方,可以当面联系我本人,或者将问题反馈到我的邮箱(chendikai1314@163.com)。希望大家能够在学习的过程中对知识点进行总结,形成自己的知识体系。

    目录

    1、Java入门、JDK安装

    1.1  Java的特点

    1.2  JDK的安装

    2.Java基础知识

    2.1  标识符和关键字

    2.2  基本数据类型

    2.3  数组类型 

    3.运算符、表达式和语句

    3.1  运算符和表达式 

    3.2  流程控制语句 

    3.2.1  顺序结构 

    3.2.2  循环结构 

    4.案例练习 

    4.1  案例一 

    4.2  案例二 

    4.3  案例三 

    5.类和对象

    5.1  类 

     5.2  对象

    6.Java三大特性、抽象类、接口 

    6.1  封装 

    6.2  继承 

    6.3  多态 

    6.4  抽象类 

    6.5  接口 

    7.内部类、Lambda表达式 

    7.1  内部类

    7.1.1  成员内部类 

    7.1.2  局部内部类 

    7.1.3  静态内部类 

    7.1.4  匿名内部类 

    7.2  Lambda表达式 

    8.UML类图和面向对象设计原则 

    8.1  UML类图 

    8.1.1  泛化关系 

    8.1.2  关联关系 

    8.1.3  依赖关系 

    8.1.4  实现关系 

    8.2  面向对象设计原则

    8.2.1  单一职责原则(SRP)

    8.2.2  开发封闭原则(OCP) 

     8.2.3  里氏替换原则 

    8.2.4  依赖倒置原则 

    9.常用实用类 

    9.1  Object 

    9.2  String 

    9.3  时间日期类 

    9.3.1  Date 

    9.3.2  Calendar 

    10.异常机制 

    10.1  异常概述 

     10.2  常见异常

    10.3  异常处理机制 

    10.3.1  try-catch-finally 

    10.3.2  throws 

    10.4  手动抛出异常 

    10.5  用户自定义异常 

    11.案例练习 

    11.1   案例一 

    11.2  案例二 

    12.输入流和输出流 

    12.1  File类的基本操作 

    12.2  字节流和字符流

    12.2.1  字节输出流 

    12.2.2  字节输入流 


    1、Java入门、JDK安装

    1.1  Java的特点

    1.2  JDK的安装

    1.jdk的下载:

    下载地址:https://www.oracle.com/technetwork/java/javase/overview/index.html

    2.环境变量配置

    配置jdk的安装目录

    path路径下添加jdk的bin目录

    配置lib目录下的dt.jar和tools.jar

    3.验证jdk是否安装和环境变量配置成功

    能够出现上面的内容则表明jdk安装和环境变量的配置没问题

    2.Java基础知识

    2.1  标识符和关键字

    1.标识符

    用来标识类名、变量名、方法名、类型名、数组名、文件名的有效字符序列称为标识符。简单地说,标识符就是一个名字。

    以下是Java关于标识符的语法规则:

    标识符由字母、下划线、美元符号和数字组成,长度不受限制标识符的第一个字符不能是数字字符标识符不能是关键字标识符不能是truefalsenull(尽管truefalsenull不是Java关键字)

    2.关键字

    关键字就是Java语言中已经被赋予特定意义的一些单词。不可以把关键字当做标识符来用

    2.2  基本数据类型

    序号

    数据类型

    位数

    默认值

    取值范围

    举例说明

    1

    byte()

    8

    0

    -2^7 - 2^7-1

    byte b = 10;

    2

    short(短整型)

    16

    0

    -2^15 - 2^15-1

    short s = 10;

    3

    int(整型)

    32

    0

    -2^31 - 2^31-1

    int i = 10;

    4

    long(长整型)

    64

    0

    -2^63 - 2^63-1

    long l = 10l;

    5

    float(单精度)

    34

    0.0

    -2^31 - 2^31-1

    float f = 10.0f;

    6

    double(双精度)

    64

    0.0

    -2^63 - 2^63-1

    double d = 10.0d;

    7

    char(字符)

    16

    0 - 2^16-1

    char c = 'c';

    8

    boolean(布尔值)

    8

    false

    truefalse

    boolean b = true;

    2.3  数组类型 

    数组就是把相同的数据类型的数据,按照顺序,组合成的复合数据类型 

    1.    声明数组

    2.    创建数组 

    3.    元素使用和数组长度 

     

     4.    数组初始化

    5.    数组引用 

    6.    遍历数组 

    public class ArrayDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int[] arr = new int[10]; for (int i = 0; i < arr.length; i++) { arr[i] = scanner.nextInt(); } for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }

    7.    操作数组元素 

    从键盘输入数据并存入数组中,然后将数组元素从小到大排序后打印到控制台中 

    package com.dingli.array; import java.util.Scanner; public class Demo02 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int[] arr = new int[5]; for (int i = 0; i < arr.length; i++) { arr[i] = scanner.nextInt(); } System.out.println("排序前的数据:"); for (int i = 0; i < arr.length; i++) { if (i == arr.length - 1) { System.out.println(arr[i]); break; } System.out.print(arr[i] + " "); } // 冒泡排序 for (int i = arr.length - 1; i >= 0; i--) { for (int j = 0; j < i; j++) { if (arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } // 打印排序后的数据 System.out.println("排序后的数据:"); for (int i = 0; i < arr.length; i++) { if (i == arr.length - 1) { System.out.println(arr[i]); break; } System.out.print(arr[i] + " "); } } }

    8.    习题 

     数据加密

    键盘录入数据,要求数据是六位的整数,现需要对数据进行加密

    加密规则如下:

            每位数字都加上5,然后除以10的余数代替该数字,再将第一位和第六位交换,第二位和第五位交换,第三位和第四位交换,请把加

    密后的数据输出到控制台 

    分析:

      A:键盘录入一个六位数

      B:对数据进行加密

          举例:456789

          把这个六位数分成个,十,百,千,万,十万存储到数组中

          int[] arr = {4,5,6,7,8,9};

          每位数字都加上5:

          arr[x] += 5;  {9,10,11,12,13,14}

          然后除以10的余数代替该数字:

          arr[x] % = 10;  {9,0,1,2,3,4}

         再将第一位和第六位交换,第二位和第五位交换,第三位和第四位交换:

         {9,0,1,2,3,4}  {4,3,2,1,0,9}

         C:输出加密后的数据

     参考答案:

    package com.hbnudingli.edu; import java.util.Scanner; public class Encryption { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 1、获取用户输入的数据 int num = scanner.nextInt(); // 2、将数据中的每位数存入数组中 int[] arr = new int[6]; // 3、对数据进行加密 for (int i = 0; i < arr.length; i++) { arr[i] = num / (int)Math.pow(10, i) % 10; arr[i] += 5; arr[i] %= 10; } // 4、输出加密后的数据 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]); } System.out.println(); } }

    3.运算符、表达式和语句

    3.1  运算符和表达式 

    1.  算术运算符

    符号

    作用

    说明

    +

    参看小学一年级

    -

    参看小学一年级

    *

    参看小学二年级,与“×”相同

    /

    参看小学二年级,与“÷”相同

    %

    取余

    获取的是两个数据做除法的余数

     2.  赋值运算符

    符号

    作用

    说明

    =

    赋值

    a=10,将10赋值给变量a

    +=

    加后赋值

    a+=b,将a+b的值给a

    -=

    减后赋值

    a-=b,将a-b的值给a

    *=

    乘后赋值

    a*=b,将a×b的值给a

    /=

    除后赋值

    a/=b,将a÷b的商给a

    %=

    取余后赋值

    a%=b,将a÷b的余数给a

    3.  自增自减运算符

    符号

    作用

    说明

    ++

    自增

    变量的值加1

    --

    自减

    变量的值减1

    4.  关系运算符

    符号

    说明

    ==

    a==b,判断ab的值是否相等,成立为true,不成立为false

    !=

    a!=b,判断ab的值是否不相等,成立为true,不成立为false

    >

    a>b,判断a是否大于b,成立为true,不成立为false

    >=

    a>=b,判断a是否大于等于b,成立为true,不成立为false

    <

    a<b,判断a是否小于b,成立为true,不成立为false

    <=

    a<=b,判断a是否小于等于b,成立为true,不成立为false

    5.  逻辑运算符

    符号

    作用

    说明

    &

    逻辑与

    a&bab都是true,结果为true,否则为false

    |

    逻辑或

    a|bab都是false,结果为false,否则为true

    ^

    逻辑异或

    a^bab结果不同为true,相同为false

    ~

    按位非

    ~a结果和a的结果正好相反

    !

    逻辑非

    !a,结果和a的结果正好相反

    &&

    短路与

    作用和&相同,但是有短路效果

    ||

    短路或

    作用和|相同,但是有短路效果

    6.  三目运算符

    7.  习题 

     分析:

    a.定义三个变量用于保存和尚的身高,单位为cm,这里仅仅体现数值即可 

    int height1 = 150; int height2 = 210; int height3 = 165;

    b.用三元运算符获取前两个和尚的较高身高值,并用临时身高变量保存起来 

    (height1 > height2) ? height1 : height2;

    c.用三元运算符获取临时身高值和第三个和尚身高较高值,并用最大身高变量保存 

    (tempHeight > height3) ? tempHeight : height3;

    d.输出结果  

    参考答案: 

    package com.hbnudingli.edu; public class Demo04 { public static void main(String[] args) { int height1 = 150; int height2 = 170; int height3 = 210; int temp = 0; // temp = height1 > height2 ? height1 : height2; // temp = temp > height3 ? temp : height3; temp = (height1 > height2 ? height1 : height2) > height3 ? (height1 > height2 ? height1 : height2) : height3; System.out.println("最大值:" + temp); } }

    3.2  流程控制语句 

    流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。 

    流程语句的分类 

    顺序结构 分支结构 (if,switch)循环结构 (for,while,do...while)

    3.2.1  顺序结构 

    顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码的先后顺序,依次执行,程序中大多数的代码 

    都是这样执行的。 

    1.  顺序结构执行流程图: 

    2.  if语句格式1 

     

    3.  if语句格式2 

    4.  if语句格式3 

    5.  习题 

    分析: 

    定义三个变量用于保存对象的身高,财富,颜值,这里仅仅体现数值即可  int height = scanner.nextInt(); double wealth= scanner.nextDouble(); boolean appearance = scanner.nextBoolean(); if判断对象的身高,财富,颜值是否达到心中标准 

           if(height>180 ){}

                            ….

    输出结果 

    参考答案: 

    package com.dingli.edu; import java.util.Scanner; public class Marry { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int height = scanner.nextInt(); double wealth = scanner.nextDouble(); boolean appearance = scanner.nextBoolean(); if (height > 180 && wealth > 10000 && appearance) { System.out.println("直接嫁了!!!!"); } else if (height > 180 || wealth > 10000 || appearance) { System.out.println("勉强嫁了!!!!"); } else { System.out.println("不嫁了!"); } } }

    6.  switch语句 

    注意: switch()的参数类型可以是:int,byte,short;String;char;enum

     7.  习题

     

    分析: 

    定义一个变量用于接受输入的月份 int month= scanner.nextInt();  switch判断月份:

            switchmonth){

                  case 3:

                  case 4:

                  case 5:Sys.out.print(“春暖花开”)break;

                  ….

           }

    输出结果 

    参考答案: 

    package com.dingli.edu; import java.util.Scanner; public class Sesson { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int month = scanner.nextInt(); switch (month) { case 3: case 4: case 5: System.out.println("春天到了!!!!"); break; case 6: case 7: case 8: System.out.println("夏天来了!!!"); case 9: case 10: case 11: System.out.println("秋天近了!!!"); case 12: case 1: case 2: System.out.println("冬天"); } } }

    3.2.2  循环结构 

    1.  for循环语句格式 

    2.  while循环语句格式 

    3.  do...while语句格式 

    4.  三种循环的区别 

    5.  循环嵌套 

    将一个循环放在另一个循环体内,就形成了嵌套循环。其中, for ,while ,do…while均可以作为外层循环或内层循环。   

    实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环, 

    才可结束外层的当次循环,开始下一次的循环。 

    设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次。 

     6.  跳转语句

    continue  用在循环中,基于条件控制,跳过某次循环体内容的执行,继续下一次的执行 break  用在循环中,基于条件控制,终止循环体内容的执行,也就是说结束当前的整个循环 

    7.  习题 

    分析: 

    首先需要有一个要猜的数字,使用随机数生成该数字,范围1100 因为无法预知几次能够猜中,因此猜数字这个操作应该是反复进行的,需要使用循环,而while循环通常用于描述未知循环次数的循环使用程序实现猜数字,每次均要输入猜测的数字值,需要使用键盘录入实现 比较输入的数字和系统产生的数据,需要使用分支语句。这里使用if..else..if..格式,根据不同情况进行猜测结果显示,当猜中后使用break结束循环即可 

    参考答案: 

    package com.hbnudingli.edu; import java.util.Random; import java.util.Scanner; public class Demo06 { public static void main(String[] args) { Random random = new Random(); int num = random.nextInt(100) + 1; Scanner scanner = new Scanner(System.in); while (true) { int number = 0; try { number = Integer.parseInt(scanner.next()); } catch (Exception e) { System.out.println("您脾气过于暴躁,不适合智力游戏,去玩俄罗斯方块吧!!!"); break; } if (number > num) { System.out.println("您输入的数据过大!"); } else if (number < num) { System.out.println("您输入的数据过小!"); } else { System.out.println("恭喜您猜对了!!!!!"); break; } } } }

    8.  习题 

    参考答案: 

    package com.hbnudingli.edu; public class Mutl { public static void main(String[] args) { for (int i = 1; i <= 9; i++) { for (int j = 1; j <= i; j++) { if (j == i) { System.out.print(j + "*" + i + "=" + i*j); break; } System.out.print(j + "*" + i + "=" + i*j + "\t"); } System.out.println(); } } }

    4.案例练习 

    4.1  案例一 

    分析: 

    先把三位数的每一位获取到 将获取到的个位、十位、百位的立方进行求和将上一步的和与三位数本身进行比较,看是否相等,如果相等,则为水仙花数 

    参考答案: 

    package com.dingli.edu; public class Flower { public static void main(String[] args) { System.out.println("For循环实现水仙花数:"); flower_method1(); System.out.println(); System.out.println("While循环实现水仙花数:"); flower_method2(); System.out.println(); System.out.println("do...while循环实现水仙花数:"); flower_method3(); System.out.println(); } private static void flower_method3() { int i = 100; do { int ge = i % 10; int shi = i / 10 % 10; int bai = i / 10 / 10 % 10; if (ge * ge * ge + shi * shi * shi + bai * bai * bai == i) { System.out.print(i + "\t"); } i++; } while (i < 1000); } private static void flower_method2() { int i = 100; while (i < 1000) { int ge = i % 10; int shi = i / 10 % 10; int bai = i / 10 / 10 % 10; if (ge * ge * ge + shi * shi * shi + bai * bai * bai == i) { System.out.print(i + "\t"); } i++; } } private static void flower_method1() { for (int i = 100; i < 1000; i++) { int ge = i % 10; int shi = i / 10 % 10; int bai = i / 10 / 10 % 10; if (ge * ge * ge + shi * shi * shi + bai * bai * bai == i) { System.out.print(i + "\t"); } } } }

    4.2  案例二 

    分析:

    从键盘输入年、月、日,用三个变量进行接收  int year = scanner.nextInt(); int month = scanner.nextInt(); int day=scanner.nextInt(); 当月之前的所有月份天数之和再加上输入的天数,就为该年中的天数  int count = 0; int days = 0; for (int i = 1; i < month; i++) { switch (i) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days = 31; break; case 4: case 6: case 9: case 11: days = 30; break; case 2: { if ((year % 100 != 0 && year % 4 == 0) || (year % 100 == 0 && year % 400 == 0)) { days = 29; } else { days = 28; } break; } default: break; } count += days; } 输出结果 

    参考答案: 

    package com.dingli.edu; import java.util.Scanner; /** * 输入某年某月某日,判断该天是今年的第几天 */ public class DaysOfYear { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入年份:"); int year = scanner.nextInt(); System.out.println("请输入月份:"); int month = scanner.nextInt(); System.out.println("请输入日:"); int day = scanner.nextInt(); int count = 0; int days = 0; for (int i = 1; i < month; i++) { switch (i) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days = 31; break; case 4: case 6: case 9: case 11: days = 30; break; case 2: { if ((year % 100 != 0 && year % 4 == 0) || (year % 100 == 0 && year % 400 == 0)) { days = 29; } else { days = 28; } break; } default: break; } count += days; } System.out.println("这是" + year + "的第" + (count + day) + "天"); } }

    4.3  案例三 

    分析: 

    先输入变量n,m,k的值  System.out.println("请输入玩游戏的人数:"); int n = scanner.nextInt(); System.out.println("第一个报数的人编号:"); int k = scanner.nextInt(); System.out.println("报数数字离开:"); int m = scanner.nextInt(); 当剩余人数大于0时,一直循环报数,对于已经退出的学生做好标记,不纳入报数,当报数达到m的该人员退出计数,并且计数重新开始 

    参考答案: 

    package com.dingli.edu; import java.util.Scanner; public class JsonpCircle { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入玩游戏的人数:"); int n = scanner.nextInt(); System.out.println("第一个报数的人编号:"); int k = scanner.nextInt(); System.out.println("报数数字离开:"); int m = scanner.nextInt(); int[] person = new int[n]; int[] req = new int[n]; for (int i = 0; i < n; i++) { int index = k; for (int j = 0; j < m; index++) { if (person[index % n] == 0) { j++; } } person[(index - 1) % n] = 1; req[i] = (index - 1) % n; k = index % n; } for (int a: req) { System.out.print(a + " "); } } }

    5.类和对象

    5.1  类 

     是一组具有相同属性和行为的对象的抽象 

    public class Heroes { private String name; private String role; static int roleId; final static double PI = 3.1415926; public Heroes(String name, String role) { this.name = name; this.role = role; } public Heroes() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public void fight(String message) { int id = 0; System.out.println("fight..." + id + ":" + message); } public static void bloodReturning(String home) { System.out.println("回血:" + home); } }

     1.  包

    Java 中使用 package 语句定义包,package 语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句,并且  

    package 语句适用于所有类型(类、接口、枚举和注释)的文件。定义包语法格式如下: 

    package 包名; 

    Java 包的命名规则如下: 

    包名全部由小写字母(多个单词也全部小写) 如果包名包含多个层次,每个层次用“.”分割 包名一般由倒置的域名开头 自定义包不能以 java 开头 

    包的使用: 

    a.在要引用的类名前带上包名作为修饰符 

    cn.chendikai.edu.Person person = new cn.chendikai.edu.Person();

    b.在文件开头使用import引用包中的类 

    import cn.chendikai.edu.Person;

    c.在文件前使用import引用整个包 

    import cn.chendikai.edu.*;

     java常见包:

    说明

    java.lang

    Java 的核心类库,包含运行 Java 程序必不可少的系统类,如基本数据类型、基本数学函数、 字符串处理、异常处理和线程类等,系统默认加载这个包

    java.io

    Java 语言的标准输入/输出类库,如基本输入/输出流、文件输入/输出、过滤输入/输出流等

    java.util

    包含如处理时间的 Date 类,处理动态数组的 Vector 类,以及 Stack HashTable

    java.awt

    构建图形用户界面(GUI)的类库,低级绘图操作 Graphics 类、图形界面组件和布局管理 (如 Checkbox 类、Container 类、LayoutManger 接口等),以及用户界面交互控制和事 件响应(如 Event 类)

    java.awt.image

    处理和操纵来自网上的图片的 Java 工具类库

    java.wat.peer

    很少在程序中直接用到,使得同一个 Java 程序在不同的软硬件平台上运行

    java.net

    实现网络功能的类库有 Socket 类、ServerSocket

    java.lang.reflect

    提供用于反射对象的工具

    java.util.zip

    实现文件压缩功能

    java.awt.datatransfer

    处理数据传输的工具类,包括剪贴板、字符串发送器等

    java.sql

    实现 JDBC 的类库

    java.rmi

    提供远程连接与载入的支持

    java. security

    提供安全性方面的有关支持

    2.  成员变量、局部变量、静态变量的区别 

     

    成员变量

    局部变量

    静态变量

    定义的位置

    类中,方法外

    方法中,或者方法的形式参数

    在类中,方法外

    初始化值

    有默认初始化值

    ,先定义,赋值后才能使用

    有默认初始化值

    调用方式

    对象调用

     

    对象调用,类名调用

    存储位置

    堆中

    栈中

    方法区

    生命周期

    与对象共存亡

    与方法共存亡

    与类共存亡

    别名

    实例变量

     

    类变量

     3 .权限修饰符

     

    public

    protected

    default

    private

    同一个类

    同一个包

     

    子类

     

    不同包

     

     

     

    4 . 方法重载

    就是在同一个类中,方法的名字相同,参数列表不同(顺序不同、个数不同、类型不同),实现相似的功能,与修饰符、返

    回值类型无关。 

    public class OverLoad { public static void main(String[] args) { sum(5, 8); sum(4.5, 6.5); sum(1, 5, 2.3); } public static void sum(int a, int b) { int sum = a + b; System.out.println(sum); } public static void sum(double c, double d) { double sum = c + d; System.out.println(sum); } public static void sum(int e, int f, double g) { double sum = e + f + g; System.out.println(sum); } }

    5.参数传值 

    8大基本数据类型,参数传递过程采用值拷贝的方式 

    public class Demo { public static void main(String[] args) { int a = 10; change(a); System.out.println("main方法中a的值:" + a); } public static void change(int a) { a = a * 2; System.out.println("change方法中a的值:" + a); } }

    参数类型为引用类型,参数传递的过程采用引用拷贝的方式 

    public class Demo { public static void main(String[] args) { Test test = new Test(10); change(test); System.out.println("main方法中a的值:" + test.a); } public static void change(Test test) { test.a = test.a * 2; System.out.println("change方法中a的值:" + test.a); } } class Test { public int a; public Test(int a) { this.a = a; } }

     6.this关键字

    关键字this表示当前对象,引用对象自身。 可以用于访问实例的数据域, 尤其是实例变量和局部变量同名时,进行分辨。除

    此之外,可以在构造方法内部调用同一个类的其他构造方法  

    public class ThisTest { public String name; public int age; public ThisTest(String name, int age) { this.name = name; this.age = age; } public void say() { String name = "chendikai"; System.out.println("name:" + this.name); } public static void main(String[] args) { ThisTest thisTest = new ThisTest("1810", 20); thisTest.say(); } }

     5.2  对象

    对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象 

    对象的创建格式 

    1.  格式一:声明并实例化对象 

                类名称  对象名称 = new 类名称(); 

    2.  格式:先声明对象,然后实例化对象 

                       类名称  对象名称 = null;

                       对象名称 = new 类名称();

    引用数据类型与基本数据类型最大的不同在于:引用数据类型需要内存的分配和使用。所以,关键字new的主要功能就是分

    配内存空间,也就是说,只要使用引用数据类型,就要使用关键字new来分配内存空间  

    6.Java三大特性、抽象类、接口 

    6.1  封装 

    面向对象程序设计的核心就是封装,在面向对象程序设计中,封装是通过把一组数据和与数据有关的操作集合放在一起形成对

    象。  

    public class Heroes { private String name; private String role; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public void fight(String message) { int id = 0; System.out.println("fight..." + id + ":" + message); } public static void bloodReturning(String home) { System.out.println("回血:" + home); } }

    封装特点 

    6.2  继承 

    继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展

    新的能力  

     

    继承格式 

    1.  子类的继承性 

    子类与父类在同个包中 

    子类继承父类除了private成员 

    子类与父类在不同包中 

    子类继承父类除了private、友好成员 

    protected成员 

    若子类与祖先类同包,子类可访问 

     2.  子类对象构造过程

    子类对象在实例化时,子类对象会默认先调用父类中的无参构造函数,然后再调用子类构造构造方法 

    3.  继承的限制 

    一个子类只能够继承一个父类,存在单继承局限在一个子类继承的时候,实际上会继承父类之中的操作(属性、方法)实例化子类对象时,先初始化父类中的属性,再初始化子类中的属性 

    6.3  多态 

    所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序 

    运行期间才确定。一句话总结:父类引用指向子类对象 

    1.  多态 

    定义一个Heroes父类 

    public class Heroes { int roleId = 001; public void run() { System.out.println("英雄移动..."); } }

    定义一个HouYi子类,继承自Heroes父类 

    public class HouYi extends Heroes { int roleId = 002; public void run() { System.out.println("后羿移动..."); } public void bloodReturning() { System.out.println("后羿回血..."); } }

    定义一个DaJi子类,继承自Heroes父类 

    public class DaJi extends Heroes { int roleId = 003; public void run() { System.out.println("妲己移动..."); } }

    写一个测试类,测试多态的特性 

    public class Test { public static void main(String[] args) { Heroes a = new HouYi(); Heroes b = new DaJi(); a.run(); System.out.println(a.roleId); b.run(); System.out.println(b.roleId); } }

    结论:

    成员变量

    编译和运行看左边

    成员方法

    编译看左边,运行看右边

    2.  多态的必要条件 

    3.  重载和重写的区别 

    重载发生在本类,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关 

    重写发生在父类子类之间,方法名相同,参数相同,但是具体的实现不同 

    重载和重写对比 

     

    重写(Overriding

    重载(Overloading

    类的数量

    父子类,接口与实现类

    本类

    方法名称

    一致

    一致

    参数列表

    一定不能修改

    必须修改

    返回值类型

    一定不能修改

    可以修改

    异常

    可以减少或删除,但不能扩展

    可以修改

     4.  多态的优点

    6.4  抽象类 

    用关键字abstract修饰的类称为抽象类 

     1.  抽象类的特点 

    抽象类不能被实例化,只能被继承 包含抽象方法的类一定是抽象类,但抽象类不一定包含抽象方法(抽象类可以包含普通方法)抽象方法的权限修饰符只能为public或者protected,默认情况下为public 一个类继承于一个抽象类,则子类必须实现抽象类的抽象方法,如果子类没有实现父类的抽象方法,那子类必须定义为抽象类 抽象类可以包含属性、方法、构造方法,但构造方法不能用来实例化对象,只能被子类调用 

    2.  抽象类不能和哪些关键字共存 

    6.5  接口 

    接口(interface)是抽象方法和常量值的定义的集合。

    从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现

    public interface Computer { int id = 1; public void start(); public void run(); public void stop(); }

    1.  接口的特点 

     接口中的所有成员变量都默认是由public static final修饰的接口中的所有方法都默认是由public abstract修饰的 接口没有构造方法  实现接口的类中必须提供接口中所有方法的具体实现内容 接口也可以继承另一个接口,使用extends关键字 与继承关系类似,接口与实现类之间存在多态性

    2.  接口和抽象类的对比 

     

    抽象类

    接口

    默认的方法实现

    它可以有默认的方法实现

    接口完全是抽象的。它根本不存在方法的实现

    实现

    子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的抽象方法的实现

    类使用关键字impements来实现接口。它需要提供接口中所有声明的方法的实现

    构造器

    抽象类可以有构造器

    接口不能有构造器

    与正常java类的区别

    除了不能实例化抽象类之外,它和普通java类没有任何区别

    接口是完全不同的类型

    访问修饰符

    抽象方法可以有pubic、protecteddefault这些修饰符

    接口方法默认修饰符是public。不可以使用其它修饰符

    main方法

    抽象方法可以有main方法并且我们可以运行它

    接口没有main方法,因此我们不能运行它

    多继承

    抽象类可以继承一个类和实现多个接口

    接口只可以继承一个或多个其它接口

    添加新方法

    如果你往抽象类中添加新的方法,你可以给它提供默认的实现,因此你不需要改变你现在的代码

    如果你往接口中添加方法,那么你必须改变实现接口的类

    7.内部类、Lambda表达式 

    7.1  内部类

    内部类:就是在一个类中定义一个类。 

    内部类的定义格式 

     内部类的访问特点

    内部类可以直接访问外部类的成员,包括私有 外部类要访问内部类的成员,必须创建对象 

    7.1.1  成员内部类 

    1.  成员内部类作为类的成员的角色 

    和外部类不同,Inner class还可以声明为privateprotected 可以调用外部类的结构  Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量 

    2.  成员内部类作为类的角色 

    可以在内部定义属性、方法、构造器等结构 可以声明为abstract类 ,因此可以被其它的内部类继承 可以声明为final 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类) 

    注意 

    static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式 成员内部类可以直接使用外部类的所有成员,包括私有的数据  当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的 

    成员内部类案例一: 

    package cn.chendikai.edu.innerclass; import java.sql.PseudoColumnUsage; /** * 成员内部类 */ public class OuterOne { private int number = 100; public class Inner { int num = 200; public void getNum() { // number = 100; System.out.println("number在内部类中的值:" + number); } } public void test() { System.out.println(new Inner().num); } }

    成员内部类案例二: 

    package cn.chendikai.edu.innerclass; /** * 成员内部类 */ public class OuterTwo { private int number = 121; public class Inner { private int number = 212; public void getNumber(int number) { System.out.println("局部变量number:" + number); System.out.println("内部类对象的属性number:" + this.number); System.out.println("外部类对象的属性number:" + OuterTwo.this.number); } } }

    7.1.2  局部内部类 

    局部内部类格式 

    如何使用局部内部类   

    只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型 

    局部内部类的特点 

    内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类 局部内部类可以使用外部类的成员,包括私有的 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private 局部内部类不能使用static修饰,因此也不能包含静态成员 

    7.1.3  静态内部类 

    使用static关键字修饰的内部类,叫做静态内部类,也称作嵌套类 

    嵌套类和普通内部类之间最大的区别 

    普通内部类对象隐式地保存了一个引用,指向创建它的外部类对象。而嵌套类创建对象,并不需要外部类对象 不能从嵌套类的对象中访问非静态的外部类对象 普通内部类不能有static数据和static字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西 

    静态内部类案例: 

    package cn.chendikai.edu.innerclass; public class StaticInner { private static int id = 6; private static class BSection implements Section { private String name = "Hello World!"; @Override public String hello() { return name + "您好,世界!"; } public int getId() { return id; } static int x = 200; public static void test1() { } static class BInner { private String name; static void test1() { System.out.println("inner====="); } } } public static void main(String[] args) { Section section = new BSection(); section.hello(); } }

    7.1.4  匿名内部类 

    匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一 个实例。一个匿名内部类一定是在new的后面,用 

    其隐含实现一个接口或实现一个类 

    匿名内部类格式 

    匿名内部类特点 

    匿名内部类必须继承父类或实现接口 匿名内部类只能有一个对象 匿名内部类对象只能使用多态形式引用 

    匿名内部类案例 

    package cn.chendikai.edu.innerclass; public interface InterfaceTest { public void method(); } package cn.chendikai.edu.innerclass; public class Anonymousness { public static void main(String[] args) { new Anonymousness().callInner(new InterfaceTest() { @Override public void method() { System.out.println("implements for method"); } }); } public void callInner(InterfaceTest interfaceTest) { interfaceTest.method(); } }

    7.2  Lambda表达式 

    为什么使用 Lambda 表达式  

    Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用

    它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了 提升  

     Lambda表达式的标准格式

     格式(形式参数) -> {代码块}形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可 ->:由英文中画线和大于符号组成,固定写法。代表指向动作 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容 

    Lambda表达式

    语法格式一:无参,无返回值

            Runnable r2 = () -> System.out.println("Hello Lambda");

    语法格式二:Lambda 需要一个参数,但是没有返回值

            Consumer<String> con = (String x) -> System.out.println(x);

    语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”

           Consumer<String> con = (x) -> System.out.println(x);

    语法格式四:若只有一个参数,小括号可以省略不写

          Consumer<String> con = x -> System.out.println(x);

    语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值

           Comparator<Integer> com = (x, y) -> { System.out.println("函数式接口"); return Integer.compare(x, y); };

    语法格式五:有两个参数,有返回值,并且Lambda体内只有一条句, return {}都可以不写

          Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

    Lambda表达式的注意事项 

    使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法 必须有上下文环境,才能推导出Lambda对应的接口 

    Lambda表达式和匿名内部类的区别 

    所需类型不同 

    匿名内部类:可以是接口,也可以是抽象类,还可以是具体类 Lambda表达式:只能是接口 

    使用限制不同 

    如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式 

    实现原理不同 

    匿名内部类:编译之后,产生一个单独的.class字节码文件 Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成 

    8.UML类图和面向对象设计原则 

    8.1  UML类图 

    UML类图的作用是为了能够脱离语言的限制,抽象地描述各个类的信息及各个类之间的关系 

    类的UML类图由一个矩形代表,将长方形分为三层,顶层为类名,中间层为属性层,下层为行为层 

     

    8.1.1  泛化关系 

    8.1.2  关联关系 

    8.1.3  依赖关系 

    8.1.4  实现关系 

    8.2  面向对象设计原则

    8.2.1  单一职责原则(SRP)

    一个类应该有且只有一个变化的原因。单一职责原则将不同的职责分离到单独的类,每一个职责都是一个变化的中心。需求

    变化时,将通过更改职责相关的类来体现  

    遵循单一职责原的优点有

    可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多 提高类的可读性,提高系统的可维护性 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响 

    8.2.2  开发封闭原则(OCP) 

    对扩展是开放的,对修改是封闭的。开放封闭原则主要体现在下面两个方面 

    对扩展开放意味着,软件有新的需求或变化时,可以对现有的代码进行扩展,以满足新的需求 对修改封闭意味着,类一旦设计完成,就不要对类进行任何的修改 

     8.2.3  里氏替换原则 

    子类应当可以替换父类,并能出现在父类能出现的任何位置上,主要就是继承的体现。继承是一项非常优秀的语言机制,它 

    可以提高代码复用性与代码的可扩展性。这个原则的核心思想就是,良好的继承定义了一个规范 

    里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能 

    子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法 子类中可以增加自己特有的方法 当子类的方法重写父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格

    8.2.4  依赖倒置原则 

    依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。低层模块尽量都要有抽象类或 

    接口,或者两者都有。变量的声明类型尽量是抽象类或接口 

    在实际编程中,我们一般需要做到如下3点: 

    低层模块尽量都要有抽象类或接口,或者两者都有 变量的声明类型尽量是抽象类或接口 使用继承时遵循里氏替换原则 

    9.常用实用类 

    9.1  Object 

    Object类是java默认的提供的一个类,Object类是所有类的父类,也就是说任何一个类的定义的时候如果没有明确的继承一 

    个父类的话,那么它就是Object的子类 

    Object类的常用方法 

    方法名称

    类型

    描述

    toString( )

    普通

    取得对象信息

    equals()

    普通

    对象内容比较

    重写toString方法 

    package cn.dingli.edu.common; import java.util.Date; import java.util.Objects; public class DaJi { private String name; private int age; public DaJi(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "name:" + name + ";age:" + age; } }

    重写equals方法 

    package cn.dingli.edu.common; import java.util.Date; import java.util.Objects; public class DaJi { private String name; private int age; public DaJi(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "name:" + name + ";age:" + age; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (!(obj instanceof DaJi)) { return false; } else { DaJi daJi = (DaJi)obj; return this.age == daJi.age && this.name.equals(daJi.name); } } }

    【注意】 

    9.2  String 

    字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象Java 提供了 String 类来创建操作字符串。需要注意的是, 

    String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空

      

    StringStringBufferStringBuilder的区别 

    字符修改上的区别(主要) 

    String:不可变字符串 StringBuffer:可变字符串、效率低、线程安全 StringBuilder:可变字符序列、效率高、线程不安全 

    String

    StringBuffer

    StringBuilder

    String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间

    StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量

    可变类,速度更快

    不可变

    可变

    可变

     

    线程安全

    线程不安全

     

    多线程操作字符串

    单线程操作字符串

    使用场景 

    如果要操作少量的数据用 String 多线程操作字符串缓冲区下操作大量数据 StringBuffer 单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用) 

    9.3  时间日期类 

    9.3.1  Date 

    package cn.dingli.edu.common; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class Demo { public static void main(String[] args) { Date date = new Date(); long time = date.getTime(); System.out.println(time); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E"); System.out.println(simpleDateFormat.format(time)); } }

    9.3.2  Calendar 

    抽象类 Calendar 提供了一组方法,允许把以毫秒为单位的时间转换成一些有用的时间组成部分。Calendar 不能直接创建对

    象,但可以使用静态方法 getInstance() 获得代表当前日期的日历对象  

    public class CalendarDemo { public static void main(String[] args) { Calendar instance = Calendar.getInstance(); System.out.println(instance.get(Calendar.YEAR)); System.out.println(instance.get(Calendar.MONTH) + 1); System.out.println(instance.get(Calendar.DAY_OF_MONTH)); Date time = instance.getTime(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E"); System.out.println(simpleDateFormat.format(time)); } }

    10.异常机制 

    10.1  异常概述 

    异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。 (开发过程中的语法错误和逻辑错误不是异常) 

    异常体系 

    Java程序在执行过程中所发生的异常事件可分为两类 

    ErrorJava虚拟机无法解决的严重问题。如:JVM系统内部错误、资源 耗尽等严重情况。比如:StackOverflowErrorOOM。一般不编写针对性的代码进行处理 Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理 

     10.2  常见异常

    数组角标越界异常举例: 

    package cn.dingli.edu.exception; public class ArrayIndexOutOfBoundsExceptionDemo { public static void main(String[] args) { String[] str = {"test1", "test2", "test3"}; for (int i = 0; i < 4; i++) { System.out.println(str[i]); } } }

    算术异常举例 

     

    package cn.chendikai.edu.exception; public class ArithmeticExceptionDemo { public static void main(String[] args) { System.out.println(3/0); } }

    类型转换异常举例: 

    package cn.chendikai.edu.exception; import java.util.Date; public class ClassCastExceptionDemo { public static void main(String[] args) { Object obj = new Date(); ClassCastExceptionDemo classCastExceptionDemo = (ClassCastExceptionDemo)obj; System.out.println(classCastExceptionDemo); } }

    空指针异常举例: 

    package cn.chendikai.edu.exception; public class NullPointerExceptionDemo { int id = 1; public static void main(String[] args) { NullPointerExceptionDemo nullPointerExceptionDemo = new NullPointerExceptionDemo(); nullPointerExceptionDemo = null; System.out.println(nullPointerExceptionDemo.id); } }

    10.3  异常处理机制 

    Java提供的是异常处理的抓抛模型Java程序的执行过程中如出现异常,会生成一个异常类对象, 该异常对象将被提交给Java运行时系统,这个过程称为抛出 (throw)异常异常对象的生成由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样

     异常的抛出机制

    Java异常处理的方式 

    10.3.1  try-catch-finally 

    如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。

    比 如 : 可 以 用 ArithmeticException 类 作 为 参 数 的 地 方 , 就 可 以 用 RuntimeException类作为参数,或者用所有异常的 

    父类Exception类作为参数。 但不能是与ArithmeticException类无关的异常,如NullPointerException(catch 中的语句将不会执

    行)  

     异常处理案例:

    package cn.dingli.edu.exception; public class ArrayIndexOutOfBoundsExceptionDemo { public static void main(String[] args) { String[] str = {"test1", "test2", "test3"}; try { for (int i = 0; i < 4; i++) { System.out.println(str[i]); } } catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组下标越界了......"); } } }

    10.3.2  throws 

    声明抛出异常是Java中处理异常的第二种方式  

    如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理, 而由该方法的调用者负责处理 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类 

    声明抛出异常举例: 

    package cn.dingli.edu.exception; public class Demo { public static void main(String[] args) { int result = 0; try { result = divide(4, 0); } catch (ArithmeticException e) { System.out.println("======"); } } private static int divide(int i, int i1) throws ArithmeticException { return i / i1; } }

    10.4  手动抛出异常 

    Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出 

    首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运 行环境) 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误 

    手动抛出异常举例: 

    package cn.dingli.edu.exception; public class Demo { public static void main(String[] args) { int result = 0; try { result = divide(4, 0); } catch (ArithmeticException e) { System.out.println("======"); } } private static int divide(int i, int i1) { if (i1 == 0) { throw new ArithmeticException("不能被0整除"); } return i / i1; } }

    10.5  用户自定义异常 

     自定义异常格式

     

    范例 

    package cn.dingli.edu.exception; public class DefineExceptionDemo extends Exception { public DefineExceptionDemo() { } public DefineExceptionDemo(String message) { super(message); } } package cn.dingli.edu.exception; public class TestDefineExceptionDemo { public static void main(String[] args) { try { throw new DefineExceptionDemo("自定义的异常类"); } catch (DefineExceptionDemo e) { System.out.println("============"); e.printStackTrace(); } } }

    用户自定义异常的特点 

    一般地,用户自定义异常类都是RuntimeException的子类 自定义异常类通常需要编写几个重载的构造器 自定义的异常通过throw抛出 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型 

     throws throw 的区别

    11.案例练习 

    11.1   案例一 

    参考答案: 

    package cn.dingli.edu.practice; import java.util.Objects; public class User { private String username; // 用户名 private String password; // 密码 public User(String username, String password) { this.username = username; this.password = password; } @Override public boolean equals(Object o) { if (o == null) { return false; } if (this == o) { return true; } if (!(o instanceof User)) { return false; } User user = (User)o; return this.username.equals(user.username) && this.password.equals(user.password); } } package cn.dingli.edu.practice; import java.util.Scanner; public class Login { private static final int COUNT = 3; public static void main(String[] args) { User user = new User("hbnu1809", "jixin1809"); // 真实的用户名和密码 int count = 0; // 用户输入的次数 while (count < COUNT) { Scanner scanner = new Scanner(System.in); System.out.println("请输入账号:"); String username = scanner.next(); System.out.println("请输入密码:"); String password = scanner.next(); User user1 = new User(username, password); if (user1.equals(user)) { System.out.println("恭喜用户" + username + "成功登陆本系统!!!!!"); break; } count++; if (count != 3) { System.out.println("请重新输入用户名和密码"); } } if (count == COUNT) { System.out.println("你输入的次数过多,请稍后再试,或者联系系统管理员"); } } }

    11.2  案例二 

    参考答案: 

    package cn.hbnu.edu.practice; import java.util.Scanner; public class SortString { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); String[] s = str.split(" "); int[] num = new int[s.length]; try { // 获取整形数据 for (int i = 0; i < s.length; i++) { num[i] = Integer.parseInt(s[i]); } System.out.println("排序前的数据:"); for (int i = 0; i < num.length; i++) { if (i == num.length - 1) { System.out.println(num[i]); break; } System.out.print(num[i] + " "); } // 排序 for (int i = 0; i < num.length - 1; i++) { for (int j = 0; j < num.length - 1 - i; j++) { if (num[j] > num[j + 1]) { int temp = num[j]; num[j] = num[j + 1]; num[j + 1] = temp; } } } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < num.length; i++) { if (i == num.length - 1) { stringBuilder.append(num[i]); break; } stringBuilder.append(num[i] + " "); } System.out.println("排序后的数据:"); System.out.println(stringBuilder.toString()); } catch (Exception e) { System.out.println("你输入的数据中含有非数字字符串"); } } }

    12.输入流和输出流 

    12.1  File类的基本操作 

    1.  创建文件 

    package cn.chendikai.edu.InputOutput; import java.io.File; import java.io.IOException; public class CreateFile { public static void main(String[] args) { File file = new File("E:" + File.separator + "DingLi" + File.separator + "Hello.txt"); if (!file.exists()) { try { file.createNewFile(); System.out.println("文件创建成功!"); } catch (IOException e) { e.printStackTrace(); } } } }

    2.  删除文件  

    package cn.chendikai.edu.InputOutput; import java.io.File; public class DeleteFile { public static void main(String[] args) { File file = new File("E:" + File.separator + "DingLi" + File.separator + "Hello.txt"); if (file.exists()) { file.delete(); System.out.println("文件已删除!"); } else { System.out.println("文件不存在。"); } } }

    3.  遍历文件

    package cn.chendikai.edu.InputOutput; import java.io.File; public class PrintFiles { public static void main(String[] args) { File file = new File("E:" + File.separator + "DingLi"); printFiles(file); } private static void printFiles(File file) { if (file != null) { if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { printFiles(f); } } else { System.out.println(file); } } } }

    12.2  字节流和字符流

    在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些 

    数据保存起来的时候,就要使用输出流完成,程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件 

    字节流和字符流:在java.io包中,操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流

    中输出数据主要是使用OutputStream完成,输入使用的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使

    Reader类完成   

    对于字节流和字符流的理解(重点 

    字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的 所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符,而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取,以形成字节序列 字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串,字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以 字节流是最基本的,所有的InputStremOutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的,但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化,这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]String来关联在实际开发中出现的汉字问题 Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 ,如果已到达流的末尾,则返回-1.inputStreamread()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值-1。因此对于不能用0-255来表示的值就得用字符流来读取 

    操作流程 

     

    12.2.1  字节输出流 

    1.  写数据 

    package cn.chendikai.edu.InputOutput; import java.io.*; public class OutputStreamDemo { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明输出流 OutputStream outputStream = null; try { // 创建字节输出流对象 outputStream = new FileOutputStream(file); // 2、需要输出的内容 String str = "Hello chendikai"; byte[] bytes = str.getBytes(); // 因为是字节流,所以需要将字符串转为字节数组 // 3.1、将字节写入到流中 outputStream.write(bytes); } catch (IOException e) { System.out.println("文件找不到异常"); e.printStackTrace(); } finally { try { // 4、关闭输出字节流 outputStream.close(); } catch (IOException e) { System.out.println("输出流关闭异常"); e.printStackTrace(); } } } }

    一个字节一个字节的写 

    package cn.chendikai.edu.InputOutput; import java.io.*; public class OutputStreamDemo { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明输出流 OutputStream outputStream = null; try { // 创建字节输出流对象 outputStream = new FileOutputStream(file); // 2、需要输出的内容 String str = "Hello chendikai"; byte[] bytes = str.getBytes(); // 因为是字节流,所以需要将字符串转为字节数组 // 3.1、将字节写入到流中 // outputStream.write(bytes); // 3.2、一个字节一个字节的写入流中 for (int i = 0; i < bytes.length; i++) { outputStream.write(bytes[i]); } } catch (IOException e) { System.out.println("文件找不到异常"); e.printStackTrace(); } finally { try { // 4、关闭输出字节流 outputStream.close(); } catch (IOException e) { System.out.println("输出流关闭异常"); e.printStackTrace(); } } } }

    以上往文件中写数据会覆盖之前的数据,如果想往文件中追加数据,参考如下: 

    package cn.chendikai.edu.InputOutput; import java.io.*; public class OutputStreamDemo { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明输出流 OutputStream outputStream = null; try { // 创建字节输出流对象 outputStream = new FileOutputStream(file, true); // 2、需要输出的内容 String str = "Hello chendikai"; byte[] bytes = str.getBytes(); // 因为是字节流,所以需要将字符串转为字节数组 // 3.1、将字节写入到流中 // outputStream.write(bytes); // 3.2、一个字节一个字节的写入流中 for (int i = 0; i < bytes.length; i++) { outputStream.write(bytes[i]); } } catch (IOException e) { System.out.println("文件找不到异常"); e.printStackTrace(); } finally { try { // 4、关闭输出字节流 outputStream.close(); } catch (IOException e) { System.out.println("输出流关闭异常"); e.printStackTrace(); } } } }

    12.2.2  字节输入流 

    1.  读数据 

    package cn.chendikai.edu.InputOutput; import java.io.*; public class InputStreamDemo { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明字节输入流 InputStream inputStream = null; try { // 创建字节输入流对象 inputStream = new FileInputStream(file); // 2.1、读文件 byte[] bytes = new byte[1024]; int length = inputStream.read(bytes); System.out.println(new String(bytes, 0, length)); } catch (IOException e) { e.printStackTrace(); } finally { try { // 3、关闭字节输入流 inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }

    以上创建一个1024大小的字节数组比较浪费空间,修改代码如下 

    package cn.chendikai.edu.InputOutput; import java.io.*; public class InputStreamDemo { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明字节输入流 InputStream inputStream = null; try { // 创建字节输入流对象 inputStream = new FileInputStream(file); // 2.1、读文件 // byte[] bytes = new byte[1024]; // 2.2、上面的浪费空间 byte[] bytes = new byte[(int) file.length()]; int length = inputStream.read(bytes); System.out.println(new String(bytes, 0, length)); } catch (IOException e) { e.printStackTrace(); } finally { try { // 3、关闭字节输入流 inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }

    以上情况只适合知道输入文件的大小,不知道文件大小的话用如下方法 

    package cn.chendikai.edu.InputOutput; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class InputStreamDemo2 { public static void main(String[] args) { String filePath = "E:" + File.separator + "DingLi" + File.separator + "hello.txt"; File file = new File(filePath); // 1、声明字节输入流 InputStream inputStream = null; try { // 创建字节输入流对象 inputStream = new FileInputStream(file); // 2、读文件 byte[] bytes = new byte[1024]; int temp = 0; int length = 0; while ((temp = inputStream.read()) != -1) { bytes[length] = (byte) temp; length++; } System.out.println(new String(bytes, 0, length)); } catch (IOException e) { e.printStackTrace(); } finally { try { // 3、关闭字节输入流 inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    abstract assert boolean break byte case catch char class const continue default do double else enum extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw  throws transient try void volatile while

    Processed: 0.010, SQL: 9