java学习笔记

标识符


  • 所有的标识符都应该以字母(A-Z或者a-z),美元符号($)、或者下划线(_)开始
  • 首字符之后可以是字母(A-Z或者a-z),美元符号($)、或者下划线(_)或数字的任何字符组合
  • 不能使用关键字作为变量的名字或方法名。
  • 标识符是大小写敏感的
  • 合法标识符举例:age、$salary、_value、__1_value
  • 非法标识符举例:123abc、-salary、#abc
  • 可以使用中文命名,但是一般不建议这样使用,也不建议使用拼音,很low

数据类型


强类型语言

  • 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用

弱类型语言

Java的数据类型分为两大类

基本类型 (primirive type)

八大基本数据类型

public class Demo02 {
    public static void main(String[] args){
        //整数
        int = 10; //最常用,占4个字节,取值范围:-2147483648 ~ 2147483647
        byte = 20; //占1个字节,取值范围:-128 ~ 127
        short = 30; //占2个字节,取值范围:-32768 ~ 32767
        long = 30L; //占8个字节,取值范围:-9223372036854775808 ~ 9223372036854775807
        
        //小数:浮点数
        float num5 = 50.1F;//float类型要在数字后面加个F,占4个字节
        double num6 = 3.141592653589793238462643; //占8个字节
        
        //字符
        char name = '国'; //占2个字节
        //字符串,String不是关键字,类
        //String name = "秦疆";
        
        //布尔值:是非
        boolean flag = true; //占1位
        //boolean flag = false;
        
    }
}

引用类型 (reference type)

  • 类、接口、数组

什么是字节

  • 位(bit):是计算机内部数据存储的最小单位,11001100 是一个八位二进制数。

  • 字节(byte):是计算机中数据处理的基本单位,习惯上用大写 B 来表示

    • 1B(byte,字节) = 8bit(位)
  • 字符:是指计算机中使用的字母、数字、字和符号

1bit表示1位

1byte表示一个字节 1B = 8b。

1024B = 1KB

1024KB = 1M

1024KM = 1G

import java.util.Calendar;
public class Demo03 {
    public static void main(String[] args) {
        // 整数拓展: 进制      二进制  八进制:0   十进制  十六进制:0x

        int i = 10;
        int i2 = 010; // 八进制0
        int i3 = 0x10; // 十六进制0x

        System.out.println(i);
        System.out.println(i2);
        System.out.println(i3);
        System.out.println("=================================================");
        //====================================================
        // 浮点数拓展     银行业务怎么表示  钱
        //=======================================================
        //float
        //double

        float f = 0.1f;  // 0.1
        double d = 1.0/10; // 0.1

        System.out.println(f==d); //false

        float d1 = 1464513154316156161f;
        float d2 = d1 + 1;

        System.out.println(d1==d2); //true

        //=======================================
        // 字符拓展
        //=======================================
        char c1 = 'a';
        char c2 = '中';

        System.out.println(c1);
        System.out.println((int)c1); // 强制转换

        System.out.println(c2);
        System.out.println((int)c2); // 强制转换

        // 所有的字符本质还是数字
        // 编码 Unicode 表:(97 = a 65 = A) 2字节  0 ~ 65536 2^6 = 65536

        // U0000 UFFFF

        char c3 = '\u0061';
        System.out.println(c3); // a

        // 转义字符
        // \t 制表符
        // \n 换行

        System.out.println("Hello\tWorld");
        System.out.println("===============================");
        String sa = new String( original:"Hello World");
        String sb = new String( original:"Hello Wrold");
        System.out.println(sa == sb);

        String sc = "Hello World";
        String sd = "Hello World";
        System.out.println(sc == sd);
        //对象 从内存分析

        //布尔值扩展
        boolean flag = true;
        if (flag==true){} //新手
        if (flag){} //老手
        //Less is More! 代码要精简易读
    }
}

类型转换


  • 由于java是强类型语言,所以要进行有些运算的时候的,需要用到类型转换。

低 ——————————————————> 高

byte,short,char --> int --> long --> float --> double

  • 运算中,不同类型的数据先转化为同一类型,然后进行运算
  • 强类型转换
  • 自动类型转换
public class Demo03 {
    public static void main(String[] args) {
        int i = 128;
        byte b = (byte)i; // 内存溢出

        //强制转换     (类型)变量名  高-->低
        //自动转换          低-->高

        System.out.println(i);
        System.out.println(b);

        /*
        * 注意点:
        * 1、不能对布尔值进行转换
        * 2、不能把对象类型转换为不相干的类型
        * 3、在把容量转换到低容量的时候,强制
        * 4、转换的时候可能存在内存溢出,或者精度问题!
        * */
        System.out.println("============================");
        System.out.println((int)23.7);
        System.out.println((int)-45.89F);

        System.out.println("==============================");
        char c = 'a';
        int d = c+1;
        System.out.println(d);
        System.out.println((char) d);

        // 操作比较大的数的时候,注意溢出问题
        // JDK7新特性,数字之间可以用下划线分割
        int money = 10_0000_0000;
        int years = 20;
        int total = money*years; // -1474836480 , 计算的时候溢出了
        long total2 = money*years; //默认是int,转换之前已经存在问题?

        long total3 = money*years; //先把一个数转换为long
        System.out.println(total3);
    }
}

变量


  • 变量是什么:就是可以变化的量!
  • java是一种强类型语言,每个变量都必须声明其类型。
  • Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
type varName [=value] [{,varName[=value]}];
//数据类型 变量名 = 值;可以使用逗号隔开来声明多个同类型变量。
  • 注意事项:
    • 每个变量都有类型,类型可以是最基本类型,也可以是引用类型。
    • 变量名必须是合法的标识符。
    • 变量声明是一条完整的语句,因此每一个声明都必须以分号结束
public class Demo07 {
    public static void main(String[] args) {
        //int a,b,c
        int a=1;
        int b=2;
        int c=3;
        string name = "qinjiang";
        char x = 'x';
        double pi = 3.14;

    }
}

变量的作用域


  • 类变量
  • 实例变量
  • 局部变量
public class Variable{
    static int allClicks = 0;		// 类变量
    String str = "hello world";		// 实例变量
    
    public void method (){
        int i = 0;					// 局部变量
    }
}

public class Demo08 {
    // 类变量  static
    static double salary = 2500;

    // 属性:变量

    // 实例变量:从属于对象:如果不自行初始化,这个类型的默认值 0 0.0
    // 布尔值:默认是false
    // 除了基本类型,其余的默认值都是null;
    String name;
    int age;

    // main方法
    public static void main(String[] args) {

        // 局部变量
        int i = 10;
        System.out.println(i);

        // 变量类型 变量名字 = new Demo08();
        Demo08 demo08 = new Demo08();
        System.out.println(demo08.age);
        System.out.println(demo08.name);

        //类变量  static
        System.out.println(salary);

    }

    // 其他方法
    public void add(){

    }
}

常量


  • 常量(Constant): 初始化 (initialize) 后不能再改变值!不会变动的值。

  • 所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。

final 常量名 = 值;
final double PI=3.14;

常量名一般使用大写字符。

public class Demo08 {
    
    // 修饰符,不存在先后顺序
    static final doubel PI = 3.14;
    
    public static void main(String[] args) {
        System.out.println(PI);
    }
}

变量的命名规范


  1. 所有变量、方法、类名:见名知意
  2. 类成员变量:首字母小写和驼峰原则:monthSalary 除了第一个单词以外,后面的单词首字母大写 lastName
  3. 局部变量:首字母小写和驼峰原则
  4. 常量:大写字母和下划线:MAX_VALUE
  5. 类名:首字母大写和驼峰原则:Man,GoddMan
  6. 方法名:首字母小写和驼峰原则:run(),runRun()

运算符


Java语言支持如下运算:运算优先级

  • 算术运算符:+, -, *, /, %, ++,--

  • 赋值运算符 =

  • 关系运算符:>, <, >=, <=, ==, !=instanceof

  • 逻辑运算符:&&, ||, !

  • 位运算符: &, |, ^, ~, >>, <<, >>>(了解!!!)

  • 条件运算符 ? :

  • 扩展赋值运算符: +=, -=, *=, /=

public class Demo08{
    public static void main(String[] args){
        // 二元运算符
        // Ctrl + D :复制当前行到下一行
        int a = 10;
        int b = 20;
        int c = 25;
        int d = 25;
        System.out.println(a+b);
        System.out.println(a-b);
        System.out.println(a*b);
        System.out.println(a/(double)b);

    }
}

public class Demo08{
    public static void main(String[] args){
        long a = 123124124124L;
        int b = 123;
        short c = 10;
        byte d = 8;

        System.out.println(a+b+c+d); // Long
        System.out.println(b+c+d);  // int
        System.out.println(c+d);   // int
    }
}

public class Demo08{
    public static void main(String[] args){
        // 关系运算符返回的结果:正确,错误     布尔值

        int a = 10;
        int b = 20;
        int c = 21;

        System.out.println(c%a);

        System.out.println(a>b);
        System.out.println(a<b);
        System.out.println(a==b);
        System.out.println(a!=b);
    }
}

public class Demo08{
    public static void main(String[] args){
        //++ -- 自增,自减  -元运算符
        int a = 3;

        int b = a++; //执行完 b = a 后在a自增
        int c = ++b; //b自增后再执行 c = b
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        // 自减同理
        // 幂运算 2^3
        double pow = Math.pow(3,2);
        System.out.println(pow);
    }
}

public class Demo08{
    public static void main(String[] args){
        // 与(and)        或(or)       非(取反)
        boolean a = true;
        boolean b = false;

        System.out.println("a && b: "+(b&&a)); // 逻辑与运算:两个变量都为真,结果才为true
        System.out.println("a || b: "+(b||a)); // 逻辑或运算:两个变量有一个为真,则结果为true
        System.out.println("!(a && b): "+!(b&&a)); // 如果是真,则变为假,如果是假则变为真

        // 短路运算
        int c = 5;
        boolean d = (c<4)&&(c++<4); // 短路测试,是否执行了c++,执行了为6,未执行则为5
        System.out.println(d);
        System.out.println(c);
    }
}

public class Demo08{
    public static void main(String[] args){
        /*
          位运算
          A = 0011 1100
          B = 0000 1101
        --------------------------------
        A&B = 0000 1100  # 对应位两个都是1才是1,否则为0
        A|B = 0011 1101  # 有一个为1则为1,否则为0
        A^B = 0011 0001  # 两个相同则为0,否则为1
        ~B  = 1111 0010  # 取反

        2*8 = 16 2*2*2*2

        效率极高 !!!
        <<  *2 左移
        >>  /2 右移

        0000 0000   0
        0000 0001   1
        0000 0010   2
        0000 0011   3
        0000 0100   4
        0000 1000   8
        0001 0000   16
        ……
        */
        System.out.println(2<<3);
    }
}

public class Demo08{
    public static void main(String[] args){
        int a = 10;
        int b = 20;

        a+=b; // a = a+b
        a-=b; // a = a-b

        System.out.println(a);

        // 字符串连接 +
        System.out.println(""+a+b);
        System.out.println(a+b+"");
    }
}

public class Demo08{
    public static void main(String[] args){
        // 三元运算符: x ? y : z
        // 果如x==true,则结果为y,否则结果为z

        int score = 50;
        String type = score < 60 ? "不及格":"及格";  //必须掌握
        System.out.println(type);

    }
}

包机制


为了更好地组织类,Java提供了包机制,用于区别类名的命名空间。

相当于文件目录,用于存放文件。

包语句的语法格式为:

package pkg1[.pkg2[.pkg3……]];

一般利用公司域名倒置作为包名:如 公司域名为:www.baidu.com-->包名为:com.baidu.www

为了能够使用某一个包的成员,我们需要再 Java 程序中明确导入该包,使用 "import" 语句可以完成此功能

import package1[.package2……].(classname|*); // *表示所有文件

学习 “阿里巴巴开发手册”

Java Doc


javadoc 命令是用来生成自己API文档的

参数信息

@author		作者名
@version	版本号	
@since		指明需要最早使用的jdk版本
@param		参数名
@return		返回值
@throws		异常抛出情况

#生成JavaDoc
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
/**
 * @author kuangshen
 * @version 1.0
 * @since 1.8
 */
public class Doc {
    /**
     * author kuangshen
     * @param name
     * @return
     * @throws Exception
     */
    public String test(String name) throws Exception{
        return name;
    }
}

百度 “idea生成doc文档”

百度 “jdk帮助文档”

2022年4月12日 p33

Scanner对象


  • 之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入,java.util.Scanner 是Java5的新特性,$\textcolor{red}{我们可以通过Scanner 类来获取用户的输入。} $

  • 基本语法:

Scanner s = new Scanner(System.in);
  • 通过 Scanner 类的 nest() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要使用 hasNext() 与 hasNextLine() 判断是否还有输入的数据。
package scanner;

import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
        // 创建一个扫描器对象,用于接收键盘数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("使用next方式接收:");

        // 判断用户有没有输入字符串
        if (scanner.hasNext()){
            // 使用next方式接收
            String str = scanner.next();
            System.out.println("输出的内容为:" + str);
        }
        //凡是属于IO流的类如果不关闭会一直占用资源。要养成好习惯用完就关闭
        scanner.close();
    }
}
package scanner;

import java.util.Scanner;

public class Demo02 {
    public static void main(String[] args) {
        // 从键盘接收数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("属于nextLine方式接收:");

        // 判断是否还有输入
        if (scanner.hasNextLine()){
            String str = scanner.nextLine();
            System.out.println("输出的内容为:" + str);
        }
        scanner.close();
    }
}

Scanner 对象


next():

  1. 一定要读取到有效字符后才恶意结束输入。
  2. 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
  3. 只对输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  4. $\textcolor{red}{next() 不能得到带有空格的字符串。}$

nextLine():

  1. 以Enter为结束符也就是说 nextLine() 方法返回的是输入回车之前的所有字符。
  2. 可以获取空白。
package scanner;

import java.util.Scanner;

public class Demo03 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入数据:");
        String str = scanner.nextLine();
        System.out.println("输出的内容为:" + str);
        scanner.close();
    }
}
package scanner;

import java.util.Scanner;

public class Demo04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 从键盘接收数据
        int i = 0;
        float f = 0.0f;

        System.out.println("请输入整数:");

        // 如果……那么……
        if (scanner.hasNextInt()){
            i = scanner.nextInt();
            System.out.println("整数数据: " + i);
        }else{
            System.out.println("输入的不是整数数据!");
        }

        System.out.println("请输入小数:");

        if (scanner.hasNextFloat()){
            f = scanner.nextFloat();
            System.out.println("小数数据:" + f);
        }else {
            System.out.println("输入的不是小数数据!");
        }
        scanner.close();
    }
}

package scanner;

import java.util.Scanner;

public class Demo05 {
    public static void main(String[] args) {
        // 我们可以输入多个数字,并求其总和与平均值,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果。
        Scanner scanner = new Scanner(System.in);

        // 和
        double sum = 0;
        // 计算输入了多少个数字
        int m = 0;

        // 通过循环判断是否还有输入,并在里面对每一个进行求和和统计
        while (scanner.hasNextDouble()) {
            double x = scanner.nextDouble();
            m = m + 1;
            sum = sum + x;
            System.out.println("你输入了第"+m+"个数据,然后当前结果sum="+sum);
        }
        System.out.println(m + "个数的和为" + sum);
        System.out.println(m + "个数的平均值是" + (sum / m));
        scanner.close();
    }
}

顺序结构


  • Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。

  • 顺序结构是最简单的算法结构。

  • 语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,$\textcolor{red}{它是任何一个算法都离不开的一种基本算法结构。}$

package Struct;

public class ShunXunDemo {
    public static void main(String[] args) {
        System.out.println("Hello1");
        System.out.println("Hello2");
        System.out.println("Hello3");
        System.out.println("Hello4");
        System.out.println("Hello5");
    }
}

选择结构


  • if单选择结构
  • if双选择结构
  • if多选择结构
  • 嵌套的if结构
  • switch多选择结构

if单选择结构


  • 我们很多时候需要去判断一个东西是否可行,然后我才去执行,这样一个过程在程序中用if语句来表示
  • 语法
if(布尔表达式){
    // 如果布尔表达式为true将执行的语句。
}
//示例:
    
package Struct;

import java.util.Scanner;

public class ifDemo01 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入内容:");
        String s = scanner.nextLine();

        // equals:判断字符串是否相等
        if (s.equals("Hello")){
            System.out.println(s);
        }
        System.out.println("End");

        scanner.close();
    }
}

if双选择结构


  • 现在有一个需求,公司要收购一个软件,成功了,给人支付100万元,失败了,自己找人开发。这样的需求用一个if是搞不定的,我们需要有两个判断,需要一个双选择结构,所以就有了if-else结构。

  • 语法

if(布尔表达式){
    // 如果布尔表达式的值为true
}else{
    // 如果布尔表达式的值为false
}
// 示例
package Struct;

import java.util.Scanner;

public class ifDemo02 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入成绩:");
        int score = scanner.nextInt();

        // equals:判断字符串是否相等
        if (score>60){
            System.out.println("及格");
        }else{
            System.out.println("不及格");
        }

        scanner.close();
    }
}

if多选择结构


我们发现刚才的代码不符合实际情况,真实的情况还可能存在ABCD,存在区间多级判断。比如90 ~ 100 就是A,80 ~ 90就是B……等等,在生活中我们很多时候的选择也不仅仅只有两个,所以我们需要一个多选择结构来处理这类问题!

语法:

if(布尔表达式1){
    // 如果布尔表达式1的值为true执行代码
}else if(布尔表达式2){
    // 如果布尔表达式2的值为true执行代码
}else if(布尔表达式3){
    // 如果布尔表达式3的值为true执行代码
}else{
    // 如果以上布尔表达式都不为true执行代码
}
// 示例
package Struct;

import java.util.Scanner;

public class ifDemo03 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        /*
        if 语句至多有1个 else 语句,else语句在所有的 else if 语句后。
        if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
        一旦其中一个 else if 语句检测为 true ,其他的 else if 以及 else 语句都将跳过执行。
         */
        System.out.println("请输入成绩:");
        int score = scanner.nextInt();

        // 成绩分数大于60分就是合格,小于60分就是不及格
        if (score==100){
            System.out.println("恭喜满分");
        }else if(score<100 && score >= 90){
            System.out.println("A级");
        }else if(score<90 && score >= 80){
            System.out.println("B级");
        }else if(score<80 && score >= 70){
            System.out.println("C级");
        }else if(score<70 && score >= 60){
            System.out.println("D级");
        }else if(score<60){
            System.out.println("成绩不合格");
        }else{
            System.out.println("成绩不合法");
        }

        scanner.close();
    }
}

嵌套的if结构


使用嵌套的 if...else 语句是合法的。也就是说你可以在另一个 if 或者 else if 语句中使用 if 或者 else if 语句。你可以像 if 语句一样嵌套 else if...else.

语法:

if(布尔表达式 1){
    // 如果布尔表达式 1的值为true执行代码
    if(布尔表达式 2){
        // 如果布尔表达式 2的值为true执行代码
    }
}

switch多选择结构


多选择结构还有要给实现方式就是switch case 语句。

switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

switch语句中的变量类型可以是:

byte、short、int、或者char.

$\textcolor{red}{从Java SE7 开始}$

$\textcolor{red}{switch 支持字符串 String 类型了}$

同时 case 标签必须为字符串常量或字面量。

switch(expression){
    case value :
        // 语句
        break; // 可选
    case value :
        // 语句
        break; // 可选
    // 你可以有任意数量的case语句
    default : // 可选
        // 语句
}
// 示例
package Struct;

public class SwitchDemo01 {
    public static void main(String[] args) {

        // case 穿透  switch 匹配一个具体的值
        char grade = 'C';

        switch (grade) {
            case 'A':
                System.out.println("优秀");
                break;
            case 'B':
                System.out.println("良好");
                break;
            case 'C':
                System.out.println("及格");
                break;
            case 'D':
                System.out.println("再接再厉");
                break;
            case 'E':
                System.out.println("挂科");
                break;
            default:
                System.out.println("未知等级");
        }
    }
}

package Struct;

public class SwitchDemo02 {
    public static void main(String[] args) {

        // JDK7的新特性,表达式结果可以是字符串!!!
        // 字符的本质还是数字

        // 反编译 java ---calss(字节码) --- 反编译(IDEA)


        String name = "秦疆";

        switch (name) {
            case "秦疆":
                System.out.println("秦疆");
                break;
            case "狂神":
                System.out.println("狂神");
                break;
            default:
                System.out.println("弄啥嘞!");
        }
    }
}

循环结构


  • while 循环
  • do...while 循环
  • for 循环
  • 在Java5中引入了一种主要用于数组的增强型for循环

while 循环


  • while 是最基本的循环,它的结构为:
while( 布尔表达式 ){
    // 循环内容
}
  • 只要布尔表达式为true,循环就会一直执行下去。
  • 我们大多数情况是会让循环停止下来的,我们需要一个让表达式生效的方式来结束循环。
  • 少部分情况需要循环一直执行,比如服务器的请求响应监听
  • 循环条件一直为true就会造成无限循环【死循环】,我们正常的业务编程中该尽量避免死循环。会影响程序性能或者造成程序卡死奔溃!
package com.kuang.struct;

public class WhileDemo01 {
    public static void main(String[] args) {
        // 输出1~100
        int i = 0;
        while (i<100){
            i++;
            System.out.println(i);
        }
    }

}
package com.kuang.struct;

public class WhileDemo03 {
    public static void main(String[] args) {
        // 计算 1+2+3+……+100=?

        int i = 0;
        int sum = 0;

        while(i<100){
            i++;
            sum = i + sum;
        }
        System.out.println(sum);
    }
}
//或
package com.kuang.struct;

public class WhileDemo03 {
    public static void main(String[] args) {
        // 计算 1+2+3+……+100=?

        int i = 0;
        int sum = 0;

        while(i<=100){
            sum = i + sum;
            i++;
        }
        System.out.println(sum);
    }
}

do...while 循环

  • 对与 while 语句而言,如果不满足条件,则不能进入循环。但是有时候我们需要即使不满足条件也至少执行一次。
  • do...while 循环和 while 循环相似,不同的是, do...while 循环至少执行一次。
do {
    // 代码语句
}while(布尔表达式);
  • While和do-While的区别:
    • while先判断后执行。do-while先执行后判断。
    • Do...while 总是保证循环体会被至少执行一次!这是他们的主要差别。
package com.kuang.struct;

public class DoWhileDemo01 {
    public static void main(String[] args) {
        int i = 0;
        int sum = 0;

        do {
            i++;
            sum=sum+i;
        }while (i<100);
        System.out.println(sum);
    }
}

package com.kuang.struct;

public class DoWhileDemo02 {
    public static void main(String[] args) {
        int a = 0;
        while (a<0){
            System.out.println(a);
            a++;
        }
        System.out.println("=====================");
        do {
            System.out.println(a);
            a++;
        }while (a<0);
    }
}

For 循环


  • 虽然所有循环结构都可以用 while 或者 do...while 表示,但 Java 提供了另一种语句,for 循环,使一些循环结构变得更加简单。
  • for 循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
  • for 循环执行的次数是在执行前就确定的。语法格式如下:
for(初始化;布尔表达式;更新){
    // 代码语句
}

练习

  1. 计算0到100之间的奇数和偶数的和。
  2. 用 while 或 for 循环输出1~1000之间能被5整除的数,并且每行输出3个。
  3. 打印九九乘法表。
package com.kuang.struct;

public class ForDemo01 {
    public static void main(String[] args) {
        int a = 1; // 初始化条件

        while (a<=100){ // 条件判断
            System.out.println(a); //循环体
            a+=2;
        }
        System.out.println("while循环结束!");

        //初始化--条件判断--迭代
        for (int i = 1;i<=100;i++){
            System.out.println(i);
        }
        System.out.println("for循环结束!");

        /*
        关于 for 循环有以下几点说明:

        最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
        然后,检测布尔表达式的值。如果为true,循环体被执行,如果为false,循环终止,开始执行循环体后面的语句。
        执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)。
        再次检测布尔表达式。循环执行上面的过程。
         */
        // 死循环
//        for (;;){
//
//        }
    }
}
// 计算0到100之间的奇数和偶数的和
package com.kuang.struct;

public class ForDemo02 {
    public static void main(String[] args) {
        // 练习1: 计算0到100之间的奇数和偶数的和

        int oddSum = 0;
        int evenSum = 0;

        for (int i = 0; i <= 100; i++) {
            if (i%2 != 0){  // 奇数
                oddSum+=i; //oddSum = oddSum + i;
            }else { // 偶数
                evenSum+=i;
            }
        }
        System.out.println( "奇数的和为:" + oddSum );
        System.out.println( "偶数的和为:" + evenSum );
    }
}
// 用 while 或 for 循环输出1~1000之间能被5整除的数,并且每行输出3个。
package com.kuang.struct;

public class ForDemo03 {
    public static void main(String[] args) {
        // 用 while 或 for 循环输出1~1000之间能被5整除的数,并且每行输出3个。

        for (int i = 0; i <= 1000; i++) {
            if (i%5 == 0){
                System.out.print(i + "\t");
            }
            if (i%(5*3) == 0){
                System.out.println();
                // System.out.print("\n");
            }
        }
    }
}
// 打印九九乘法表
package com.kuang.struct;

public class ForDemo04 {
    public static void main(String[] args) {
        //打印九九乘法表
        // 1、我们先打印第一列,这个大家应该都会
        // 2、我们把固定的1再用一个循环包起来
        // 3、去掉重复项,i <= j
        // 4、调整样式

        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print(i + "*" + j + "=" + (i*j) + "\t");
            }
            System.out.println();
        }
    }
}

增强for循环


  • 这里我们先只是见一面,做个了解,之后数组我们重点使用
  • Java5 引入了一种主要用于数组或集合的增强型 for 循环。
  • Java 增强 for 循环语法格式如下:
for(声明语句:表达式){
    // 代码句子
}
  • 声明语句: 声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定再循环语句块,其值与此时数组元素的值相等。
  • 表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
package com.kuang.struct;

public class ForDemo05 {
    public static void main(String[] args) {
        int[] numbers = {10,20,30,40,50}; // 定义了一个数组

        for (int i = 0;i<5;i++){
            System.out.println(numbers[i]);

        }
        System.out.println("=============");
        // 遍历数组的元素
        for (int x:numbers){
            System.out.println(x);
        }
    }
}

break & continue


  • break 在任何循环语句的主体部分,均可用 break 控制循环的流程。$\textcolor{red}{break 用于强行推出循环}$,不执行循环中剩余的语句。(break语句也在 switch 语句中使用)
  • continue 语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。

关于goto关键字

  • goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但并未在语言中得到正式使用;Java没有goto。然而,在 break 和 continue 这两个关键字的身上,我们仍然能看出一些goto的影子-----带标签的break 和 continue。
  • ”标签“ 是指后面跟一个冒号的标识符,例如: lable:
  • 对 Java 来说唯一用到标签的地方是在循环语句之前。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break 和 continue 关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
package com.kuang.struct;

public class BreakDemo {
    public static void main(String[] args) {
        int i = 0;
        while(i<100){
            i++;
            System.out.println(i);
            if (i==30){
                break; // 跳出循环但不终止循环循环体外的程序
            }
        }
        System.out.println("123");
    }
}
package com.kuang.struct;

public class ContinueDomo {
    public static void main(String[] args) {
        int i = 0;
        while (i<100) {
            i++;
            if (i % 10 == 0) {
                System.out.println();
                continue;
            }
            System.out.println(i);
        }

        // break 在任何循环语句的主题部分,均可用 break 控制循环的流程。
        // break 用于强制退出循环体,不执行循环中剩余的语句。(break 语句也在switch 语句中使用)
        // continue 语句用在循环语句中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
    }
}
package com.kuang.struct;

public class LabelDemo {
    public static void main(String[] args) {
        // 打印101~102之间所有的质数
        // 质数是指大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的自然数。

        int count = 0;
        // 不建议使用
        outer:for (int i = 101;i<150;i++){
            for (int j = 2;j<i/2;j++){
                if (i % j == 0){
                    continue outer;
                }
            }
            System.out.println(i+" ");
        }
    }
}

练习


package com.kuang.struct;

public class TextDemo {
    public static void main(String[] args) {
        // 打印三角行   5行
        for (int i = 1; i <= 5; i++) {
            for (int j = 5; j >= i; j--) {
                System.out.print(" ");
            }
            for (int j = 1;j<=i;j++){
                System.out.print("*");
            }
            for (int j = 1;j<i;j++){
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

CONTENTS(目录)

  1. 何为方法
  2. 方法的定义及调用
  3. 方法重载
  4. 命令行传参
  5. 可变参数
  6. 递归

何为方法


  • System.out.println();,那么它是什么呢?
  • Java犯法是语句的集合,它们在一起执行一个功能。
    • 方法是解决一类问题的步骤的有序组合
    • 方法包含于类或对象中
    • 方法在程序中被创建,在其他地方被引用
  • 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,$\textcolor{red}{就是一个方法只完成1个功能,这样利于我们后期的扩展。}$

回顾方法的命名规则?

  • 小驼峰命名法
package com.kuang.struct;

public class Demo01 {
    public static void main(String[] args) {
//        int sum = add(1,2);  //调用add()方法,1和2为实际参数,即实参
//        System.out.println(sum);
        text();
    }

    // 加法的方法
    public static int add(int a,int b){ // a,b 为形式参数,即形参
        return a + b;
    }
    public static void text(){
        for (int i = 0;i <= 1000;i++ ){
            if (i%5 == 0){
                System.out.print(i+"\t");
            }
            if (i%(5*3) == 0){
                System.out.println();
            }
        }
    }
}

方法的定义


  • Java的方法类似于其他语言的函数,是一段$\textcolor{red}{用来完成特定功能的代码片段}$,一般情况下,定义一个方法包含一下语法:
  • $\textcolor{red}{方法包含一个方法头和一个方法体。}$下面是一个方法的所有部分:
  • $\textcolor{red}{修饰符}$:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
  • $\textcolor{red}{返回值类型}$:方法可能会返回值。returnValurType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
  • $\textcolor{red}{方法名}$:是方法的实际名称。方法名和参数表共同构成方法签名。
  • $\textcolor{red}{参数类型}$:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表时指方法的参数类型、顺序和参数的个数。参数时可选的,方法可以不包含任何参数。
    • $\textcolor{red}{形式参数}$:在方法被调用时用于接收外界输入的数据。
    • $\textcolor{red}{实参}$:调用方法时实际给方法的数据。
  • $\textcolor{red}{方法体}$:方法体包含具体的语句,定义该方法的功能。

方法的结构:

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

方法的调用


调用方法:对象名.方法名(实参列表)

Java 支持两种调用方法的方式,根据方法是否返回值来选择。

当方法返回一个值的时候,方法调用通常被当做一个值。列如:

int larger = max(30,40);

如果方法返回值时void,方法调用一定是一条语句。

System.out.println("Hello,kuangshen!");

课后拓展了解:值传递(Java)和 引用传递

package com.kuang.method;

public class Demo02 {
    public static void main(String[] args) {
        int max = max(100,100);
        System.out.println(max);
    }

    // 比较大小
    public static int max(int a,int b){
        int result = 0;

        if (a==b){
            System.out.println("a == b");
            return  0; // 终止方法
        }
        if (a>b){
            result = a;
        }else{
            result = b;
        }
        return result;
    }
}

方法的重载


  • 重载就是在一个类中,有相同的函数名称,但形参不同的函数。
  • 方法的重载的规则:
    • 方法名称必须相同。
    • 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
    • 方法的返回类型可以相同也可以不相同。
    • 仅仅返回类型不同不足以成为方法的重载。
  • 实现理论:
    • 方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
package com.kuang.method;

public class Demo02 {
    public static void main(String[] args) {
        double max = max(100.1,100.3);
        System.out.println(max);
    }

    // 比较大小
    public static double max(double a,double b){
        double result = 0;

        if (a==b){
            System.out.println("a == b");
            return  0; // 终止方法
        }
        if (a>b){
            result = a;
        }else{
            result = b;
        }
        return result;
    }
    // 比较大小
    public static int max(int a,int b){
        int result = 0;

        if (a==b){
            System.out.println("a == b");
            return  0; // 终止方法
        }
        if (a>b){
            result = a;
        }else{
            result = b;
        }
        return result;
    }
}

命令行传参


有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给 main() 函数实现。

public class CommandLine {
    pbblic static void main(String args[]){
        for (int i = 0;i<args.length;i++){
            System.out.println("args[" + i + "]" + args[i]);
        }
    }
}

可变参数


JDK1.5 开始,Java 支持传递同类型的可变参数给一个方法。

在方法声明中,在指定参数类型后加一个省略号(...).

一个方法中只能指定一个可变参数,它必须时方法的最后一个参数。任何普通的参数必须在它之前声明。

package com.kuang.method;

public class Demo03 {
    public static void main(String[] args) {
        printMax(10,11,8,7,1,50,22);
    }

    public static void printMax(double... numbers){
        if (numbers.length == 0){
            System.out.println("No argument passed");
            return;
        }

        double result = numbers[0];

        // 排序!
        for (int i = 1;i < numbers.length;i++) {
            if (numbers[i] > result) {
                result = numbers[i];
            }
        }
        System.out.println("This max value is " + result);
    }

}

递归


  • A方法调用B方法,我们很容易理解!
  • 递归就是:A方法调用A方法!就是自己调用自己
  • 利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
  • 递归结构包括两个部分:
    • 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。
    • 递归体:什么时候需要调用自身方法。
package com.kuang.method;

public class Demo06 {
    public static void main(String[] args) {
        System.out.println(f(5)); // 调用方法
    }

    public static int f(int n){
        if (n == 1){
            return 1; // 直到进入这里后方方法调用结束
        }else {
            return n * f(n-1); // 进入这里会一直调f()方法
        }
    }
}

作业

写一个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。

思路:

写4个方法:加减乘除

利用循环+switch进行用户交互

传递需要操作的两个数

输出结果。

package com.kuang.method;

import java.util.Scanner;

public class CaculatorDemo01 {
    public static void main(String[] args) {
        /*
        写4个方法:加减乘除
        利用循环+switch进行用户交互
        传递需要操作的两个数
        输出结果。
        */
        while ( 1 == 1 ){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入x:");
        double x = scanner.nextDouble();
        System.out.println("请输入y:");
        double y = scanner.nextDouble();
        System.out.println("请输入str:");
        String str = scanner.next();

            //System.out.println(argument);
            switch (str){
                case "+":
                    double add = add(x,y);
                    System.out.println(x + "+" + y + "=" + add);
                    break;
                case "-":
                    double minus = minus(x,y);
                    System.out.println(x + "-" + y + "=" + minus);
                    break;
                case "*":
                    double multiply = multiply(x,y);
                    System.out.println(x + "*" + y + "=" + multiply);
                    break;
                case "/":
                    double divide = divide(x,y);
                    System.out.println(x + "/" + y + "=" + divide);
                    break;
            }
        }
    }
    static double result = 0;
    public static double add(double number1,double number2){
        return result = number1 + number2;
    }
    public static double minus(double number1,double number2){
        return result = number1 - number2;
    }
    public static double multiply(double number1,double number2){
        return result = number1 * number2;
    }
    public static double divide(double number1,double number2){
        return result = number1 / number2;
    }
}

目录(CONTENTS)

  1. 数组概念
  2. 数组声明创建
  3. 数组使用
  4. 多维数组
  5. Arrays 类
  6. 稀疏数组

数组的定义


  • 数组是相同类型数据的有序集合。
  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。
  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。

数组声明创建


首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:

dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法

Java 语言使用 new 操作符来创建数组,语法如下:

dataType[] arrayRefVar = new dataType[arraySize];

数组的元素是通过索引访问的,数组索引从0开始。

获取数组长度: arrays.length

package com.kuang.array;

public class ArrayDemo01 {
    public static void main(String[] args) {
        // 变量的类型 变量的名字 = 变量的值;
        // 数组类型

        int[] nums; // 1.声明一个数组
        nums = new int[10]; // 2.创建一个数组
        // 给数组赋值
        nums[0] = 1;
        nums[1] = 2;
        nums[2] = 3;
        nums[3] = 4;
        nums[4] = 5;
        nums[5] = 6;
        nums[6] = 7;
        nums[7] = 8;
        nums[8] = 9;
        nums[9] = 10;

        // 计算所有元素的和
        int sum = 0;
        for (int i = 0;i < nums.length;i++){
            sum += nums[i];
        }
        System.out.println("总和为:"+sum);

    }
}

三种初始化

堆:存放new的对象和数组,可以被所有的线程共享,不会存放别的对象引用

栈:存放基本变量类型(会包含这个基本类型的具体数值),引用对象的变量(会存放这个引用在堆里面的具体地址)

静态初始化

int[] a = {1,2,3};
Mna[] mans = {new Mna(1,1),new Man(2,2)};

静态初始化

int[] a = new int[2];
a[0] = 1;
a[2] = 2;

数组的默认初始化

数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐藏式初始化。

package com.kuang.array;

public class ArrayDemo02 {
    public static void main(String[] args) {
        // 静态初始化:创建 + 赋值
        int[] a = {1,2,3,4,5,6};
        System.out.println(a[0]);

        // 动态初始化:包含默认初始化
        int[] b = new int[10];
        b[0] = 10;
        b[1] = 10;
        System.out.println(b[0]);
        System.out.println(b[1]);
        System.out.println(b[2]);
        System.out.println(b[3]);
        System.out.println(b[4]);
    }
}

数组的四个基本特点

其长度式确定的。数组一旦被创建,它的大小就是不可以改变的。

其元素必须是相同类型,不允许出现混合类型。

数组中的元素可以是任何数据类型,包括基本类型和引用类型。

数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。

数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,$\textcolor{red}{数组对象本身是在堆中的。}$

数组边界

下标的合法区间:[0,length-1],如果越界就会报错;

publci static void main()[String[] args]{
    int[] a=new int[2];
    System.out.println(a[2]);
}

ArrayIndexOutOfBoundsExceprion:数组下标越界异常!

小结:

数组是相同数据类型(数据类型可以为任意类型)的有序集合

数组也是对象。数组元素相当于对象的成员变量。

数组创建完后,数组长度是确定的,不可变的。如果越界则包 ArrayIndexOutOfBoundsExceprion

package com.kuang.array;

public class ArrayDemo03 {
    public static void main(String[] args) {
        int[] arrays = {1,2,3,4,5};

        // 打印全部的数组元素
        for (int i = 0; i < arrays.length; i++) {
            System.out.println(arrays[i]);
        }
        System.out.println("===================");
        // 计算所有元素的和
        int sum = 0;
        for (int i = 0; i < arrays.length; i++) {
            sum += arrays[i];
        }
        System.out.println("sum =" + sum);

        System.out.println("=========================");
        // 查找最大元素
        int max = arrays[0];
        for (int i = 0; i < arrays.length; i++) {
            if (arrays[i]>max){
                max = arrays[i];
            }
        }
        System.out.println("数组中最大数为:" + max);
    }
}

数组的使用


普通的For循环

For-Each 循环

数组作方法入参

数组作返回值

package com.kuang.array;

public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] arrays = {1,2,3,4,5};

        //JDK1.5, 没有下标
//        for (int array:arrays){
//            System.out.println(array);
//        }
        int[] reverse = reverse(arrays);// 调用反转方法
        pringArray(reverse); // 调用打印方法
    }

    // 反转数组
    public static int[] reverse(int[] args){
        int[] result = new int[args.length];
        // 定义两个变量i,j,并使j的长度等于i。
        for (int i = 0,j = args.length-1; i < args.length; i++,j--) {
            result[j] = args[i]; // 把args的第一个元素赋值给result的最后一个元素
        }
        return result; // 返回结果
    }

    // 打印数组元素
    public static void pringArray(int[] arrays){
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i]+" "); //打印数组里的每个元素
        }
    }
}

多维数组


多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。

二维数组:

int a[][] = new int[2][5];

解析:以上二维数组 a 可以看成一个两行五列的数组。

package com.kuang.array;

public class ArrayDemo05 {
    public static void main(String[] args) {
        /*
        1,2  array[0]
        2,3  array[1]
        */
        int[][][] array = {{{1,2,6},{2,3,7}},{{3,4,8},{4,5,9}}};
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                for (int k = 0; k < array[i][j].length; k++) {
                    System.out.println(array[i][j][k]);
                }
            }

        }
    }
}

arrays 类


  • 由于数组对象本省并没有什么方法可以供我们调用,但API中提供了一个工具类 Arrays 供我们使用,从而可以对数据对象进行一些基本的操作。
  • 查看 JDK 帮助文档
  • Arrays 类中的方法都是 static 修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用(注意:是“不用”而不是“不能”)

  • 具体一下常用的功能:

  • 给数组赋值:通过 fill 方法。
  • 对数组排序:通过 sort 方法,按升序排序。
  • 比较数组:通过 equals 方法比较数组中元素值是否相等。
  • 查找数组元素:通过 binaraSearch 方法能对排序好的数组进行二分查找法操作。
package com.kuang.array;

import java.util.Arrays;

public class ArrayDemo06 {
    public static void main(String[] args) {
        int[] a = {323,3,5,45,1,4854,2,4,15};
        System.out.println(a); // 无法正常打印数组里的元素 [I@1b6d3586

        Arrays.sort(a); // 排序,升序排序,排完序后再打印
        Arrays.fill(a,2,4,0); // 数组 a[] 2到4之间用0填充
        System.out.println(Arrays.toString(a)); // 用Arrays下的toString方法可以打印a[]数组中的元素
        printArray(a);
    }
    public static void printArray(int[] a){
        for (int i = 0; i < a.length; i++) {
            if (i==0){
                System.out.print("[");
            }
            if (i==a.length-1){
                System.out.print(a[i]+"]");
            }else {
                System.out.print(a[i]+", ");
            }
        }
    }
}

冒泡排序

冒泡排序无疑是最为出名的排序算法之一,总共有八大排序!

冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人皆知。

我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为O(n2)。

package com.kuang.array;

import java.util.Arrays;


//  冒泡排序
 // 1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换它们的位置
  //2、每一次比较,都会产生出一个最大,或最小的数;
 // 3、下一轮则可以少一次排序!
  //4、依次循环,知道结束

public class ArrayDemo07 {
    public static void main(String[] args) {
        int[] a = {9,5,8,43,2,0,4,27,7,5,2,212};
        int[] sort = sort(a); // 调用完我们自己写的排序方法以后,返回一个排序后的数组
        System.out.println(Arrays.toString(sort));
    }

    public static int[] sort(int[] array){
        // 临时变量
        int temp = 0;

        // 外层循环,判断我们这个要走多少次;
        for (int i = 0; i < array.length-1; i++) {
            boolean flag = false; // 通过flag标识位减少没有意义的比较。
            // 内层循环,比较判断两个数,如果第一个数比第二个数大,则交换位置(只要比较一半就可以把数组里的数比较完)
            for (int j = 0; j < array.length-1-i ; j++) {
                if (array[j+1]>array[j]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    flag = true;
                }

            }
            if (flag==false){
                break;
            }
        }
        return array;
    }
}

稀疏数组


需求:编写五子棋游戏中,有存盘退出和续上盘的功能。

分析问题:因为该二维数组的很多值是默认值0,因此记录了很多没有意义的数据。

解决:稀疏数组

稀疏数组介绍

当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。

稀疏数组的处理方式是:

记录数组一共有几行几列,有多少个不同值

把具有不同值的元素和行列及值记录再一个小规模的数组中,从而缩小程序的规模

如下图:左边是原始数组,右边是稀疏数组

image-20220424233718029

package com.kuang.array;

public class ArrayDemo08 {
    public static void main(String[] args) {
        // 1. 创建一个二维数组 11 * 11    0:没有棋子;   1:黑棋    2:白棋
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        //输出原始的数组
        System.out.println("输出原始的数组");

        for (int[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }

        // 转换为稀疏数组保存
        // 获取有效值的个数
        int sum = 0;
        for (int i = 0;i < 11;i++){
            for (int j = 0; j < 11; j++) {
                if (array1[i][j]!=0){
                    sum++;
                }
            }
        }
        System.out.println("有效值的个数:"+sum);

        // 2、创建一个稀疏数组的数组
        int[][] array2 = new int[sum+1][3];

        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;

        // 遍历二维数组,将非零的值,存放稀疏数组中
        int count=0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j]!=0){
                    count++;
                    array2[count][0]=i;
                    array2[count][1]=j;
                    array2[count][2]=array1[i][j];
                }
            }

        }
        // 输出稀疏数组
        System.out.println("稀疏数组");

        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i][0]+"\t"
                +array2[i][1]+"\t"
                +array2[i][2]+"\t");
        }
        System.out.println("========================");
        System.out.println("还原");
        // 1、读取稀疏数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];

        // 2、给其中的元素还原它的值
        for (int i = 1; i < array2.length; i++) {
            array3[array2[i][0]][array2[i][1]] = array2[i][2];

        }
        // 3. 打印
        System.out.println("输出还原的数组");

        for (int[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt+"\t");

            }
            System.out.println();

        }
    }
}

面向对象编程


  1. Java的核心思想就是OOP
  2. 初始面向对象
  3. 方法回复和加深
  4. 面向对象三大特性
  5. 抽象类和接口
  6. 内部类及OOP实战

面向过程 和 面向对象

  • 面向过程思想

    • 步骤清晰简单,第一步做什么,第二步做什么……

    • 面对过程适合处理一些较为简单的问题

  • 面向对象思想

    • 物以类聚,分类 的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。

    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。

  • 对于描述复杂的事物,为了从宏光上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

属性加方法就是类

什么是面向对象

  • 面向对象编辑(Object-Oriented Programming,OOP)

  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。

  • 抽象

  • 三大特性:

  • 封装

  • 继承

  • 多态

从认识论角度考虑是先有对象后有类。对象,是具体的事务。类,是抽象的,是对对象的抽象

从代码运行角度考虑是现有类后有对象。雷士对象的模板。

回顾方法及加深


  • 方法的定义
    • 修饰符
    • 返回类型
    • break 和 return 的区别
    • 方法名
    • 参数名
    • 异常抛出
  • 方法的调用
    • 静态方法
    • 非静态方法
    • 形参和实参
    • 值传递和引用传播
    • this关键字
package com.OOP;
// Demo01类
public class demo01 {
    //main 方法
    public static void main(String[] args) {

    }
    /*
    * 修饰符 返回值类型 方法名(……){
    *   // 方法体
    *   return 返回值;
    * }
    * */
    // return 结束方法, 返回一个结果!
    public String sayHello(){
        return "hello,world";
    }
    public void print(){
        return;
    }
    public int max(int a ,int b){
        return a>b ? a : b; // 三元运算符!
    }

//    public void readFile(String file) throws IOException{
//
//    }

}

package com.OOP;

public class Demo02 {
    public static void main(String[] args) {
        // 实例化这个类 new
        // 对象类型 对象名 = 对象名;
        Student student = new Student();
        student.say();
    }
}

package com.OOP;

public class Demo03 {
    public static void main(String[] args) {
        // 实际参数和形式参数的类型要一一对应
       int add=Demo03.add(1,2);
        System.out.println(add);
    }
    public static int add(int a ,int b){
        return a + b;
    }
}

package com.OOP;

// 值传递
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);
        Demo04.change(a);
        System.out.println(a);

    }
    // 返回值为空
    public static void change(int a){
        a = 10;
    }
}

package com.OOP;

public class Student {
    public void say(){
        System.out.println("学生说话了!");
    }
}

package com.OOP;

// 引用传递:对象,本质还是传递值

// 对象,内存

public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name); // null
        Demo05.change(person);
        System.out.println(person.name);  // 青江
    }
    public static void change(Person person){
        // person 是一个对象:指向 ---> Persion person = new Persion();这是一个具体的人,可以改变属性!
        person.name = "青江";
    }
}
class Person{
    String name; // null
}

类与对象的关系


  • 类是一种抽象的数据类型,它是对某一类事务整体描述/定义,但是并不能代表某一个具体的事务。
    • 动物、植物、手机、电脑……
    • Person类、Pet类、Car类,这些类都是用来描述/定义某一类具体的事务应该具备的特点和行为
  • 对象是抽象概念的具体实例
    • 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例。
    • 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
package com.OOP;

// 学生类
public class Student {
     // 属性: 字段
     String name; // null
     int age; // 0

     // 方法
     public void study(){
         System.out.println(this.name+"在学习");
     }
}

package com.OOP;

public class Application {
    public static void main(String[] args) {
        // 类:抽象的,实例化
        // 类实例化后会返回一个自己的对象!
        // student 对象就是一个 Student 类的具体实例!
        Student xiaoming = new Student();
        Student xh = new Student();

        xiaoming.name = "小明";
        xiaoming.age = 3;
        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);

        xh.name = "小红";
        xh.age = 3;
        System.out.println(xh.name);
        System.out.println(xh.age);

    }
}

创建与初始化对象


  • 使用new关键字创建对象
  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的,并且构造器有一下两个特点:
    1. 必须和类的名字相同
    2. 必须没有返回类型,也不能写void
  • 构造器必须要掌握
package com.OOP;

public class Person {
    // 一个类即使什么都不写,它也会存在一个方法
    // 显示的定义构造器
    String name;
    int age;

    // 1.使用new关键字,本质是在调用构造器
    // 2.用来初始化值
    public Person(){

    }
    // 有参构造:一旦定义了有参构造,无参构造必须显示定义
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    // alt + insert 自动生成构造器
}

/*
* 构造器:
*   1、和类名相同
*   2、没有返回值
* 作用:
*   1、new 本质在调用构造方法
*   2、初始化对象的值
* 注意点:
*   1、定义有参构造之后,如果想使用无参构造,必须显示定义。
* 	this 代表当前类
* */

package com.OOP;

// 一个项目应该只存在一个main方法
public class Application {
    public static void main(String[] args) {
        //new 实例化了一个对象
//        Person person = new Person();
//        person.name = "狂神";
        Person person = new Person("kuangshen",23);
        System.out.println(person.name);
        System.out.println(person.age);

    }
}
package com.OOP;

public class Pet {
    public String name;
    public int age;

    // 无参构造
    public void shout(){
        System.out.println("叫了一声");
    }
}

package com.OOP;

// 一个项目应该只存在一个main方法
public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        Pet cat = new Pet();

        dog.name = "旺财";
        dog.age = 3;
        dog.shout();
        System.out.println(dog.name);
        System.out.println(dog.age);

        cat.name = "咪咪";
        cat.age = 3;
        cat.shout();
        System.out.println(cat.name);
        System.out.println(cat.age);
        }
}

image-20220430165351998

回顾:

1、类与对象

类是一个模板:抽象,对象是一个具体的实例

2、方法

定义、调用

3、对应的应用

应用类型: 基本类型(8大基本类型)

对象是通过引用来操作的:栈--->堆

4、属性:字段 Field 成员变量

  • 默认初始化:
    • 数字: 0 或 0.0
    • char : u0000
    • boolean: false
    • 引用: null
  • 修饰符 属性类型 属性名 = 属性值!

5、对象的创建和使用

- 必须使用 new 关键字创造对象, 构造器 Person kuangshen = new Person();
- 对象的属性 kuangshen.name
- 对象的方法 kangshen.sleep()

6、类:

​ 静态的属性 属性

​ 动态的行为 方法

封装、继承、多态

封装

该露的露,该隐藏的隐藏

我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。

封装(数据的隐藏)

通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。

记住这句话就够了:属性私有,get/set

package com.OOP.demo04;
// 类 private: 私有
public class Student {

    // 属性私有
    private String name; // 名字
    private int id; // 学号
    private char sex; // 性别
    private int age; // 年龄

    // 提供一些可以操作这个属性的方法!
    // 提供一些public 的get、set 方法

    // get 获得这个数据
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age>120 || age < 0){
            this.age = 3;
        }else{
            this.age = age;
        }

    }
}


package com.OOP;

import com.OOP.demo04.Student;

/*
1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.统一接口
4.系统可维护增加了
*/

public class Application {
    public static void main(String[] args) {

        Student s1 = new Student();

        s1.setName("秦疆");

        // 方法名,参数列表
        System.out.println(s1.getName());

        s1.setAge(144);
        System.out.println(s1.getAge());

    }
}

继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

extends 的意思是“扩展”。子类是父类的扩展。

Java 中类只有单继承,没有多继承!

继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。

继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends类表示

子类和父类之间,从意义上讲应该具有“is a ”的关系。

object 类

super -- this

方法重写

package com.OOP.demo05;

// Person 人 : 父类
public class Person {

    // public
    // protected
    // default
    // private
    private int money = 10_0000_0000;
    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }
    public void setMoney(int money){
        this.money = money;
    }
}

package com.OOP.demo05;

// Person 人 : 父类
public class Person {

    // public
    // protected
    // default
    // private
    private int money = 10_0000_0000;
    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }
    public void setMoney(int money){
        this.money = money;
    }
}

package com.OOP;

import com.OOP.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();

        student.setMoney(9999);
        System.out.println(student.getMoney());
    }
}
// this 和 supper
package com.OOP.demo05;

// 在Java中,所有的类,都默认直接或间接继承object
// Person 人 : 父类
public class Person {
    protected String name = "kuangshen";
    // 私有的东西无法被继承
    public void print(){
        System.out.println("Person");
    }

}

package com.OOP.demo05;

// 学生 is 人:派生类,子类
// 子类继承了父类,就会拥有父类的全部方法!
public class Student extends Person {
    private String name = "qinjiang";

    public void print(){
        System.out.println("Student");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }

    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}


import com.OOP.demo05.Person;
import com.OOP.demo05.Student;

public class Application {
    public static void main(String[] args) {

        Student student = new Student();
        student.test("秦疆");
        System.out.println("=========================");
        student.test1();
    }


}
package com.OOP.demo05;

// 在Java中,所有的类,都默认直接或间接继承object
// Person 人 : 父类
public class Person {

    public Person(){
        System.out.println("Person 无参构造执行了");
    }
    // 有参构造器
//    public Person(String name){
//        System.out.println("Person 无参构造执行了");
//    }
    protected String name = "kuangshen";
    // 私有的东西无法被继承
    public void print(){
        System.out.println("Person");
    }

}

package com.OOP.demo05;

// 学生 is 人:派生类,子类
// 子类继承了父类,就会拥有父类的全部方法!
public class Student extends Person {

    public Student() {
        // 隐藏代码:调用了父类的无参构造
        super(); // 调用父类构造器必须要在子类构造器的第一行。
        // super("name"); //调用父类有参构造器
        System.out.println("Student 无参构造执行了");
    }

    private String name = "qinjiang";

    public void print(){
        System.out.println("Student");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }

    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

package com.OOP;

import com.OOP.demo05.Person;
import com.OOP.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
    }
}

方法重写:
package com.OOP.demo05;

// 重写都是方法的重写,和属性无关
public class B {
    public static void test(){
        System.out.println("B=>test");
    }
}

package com.OOP.demo05;
// 继承B
public class A extends B{
    public static void test(){
        System.out.println("A=>test");
    }
}

package com.OOP;

import com.OOP.demo05.A;
import com.OOP.demo05.B;
import com.OOP.demo05.Person;
import com.OOP.demo05.Student;

public class Application {
    public static void main(String[] args) {
		// 方法的调用只和左边定义的数据类型有关
        A a = new A();
        a.test();

        // 父类的引用指向了子类
        B b = new A();
        b.test();
    }
}




// 下面这部分才是方法的重写
package com.OOP.demo05;

// 继承
public class A extends B{

    //Override 重写
    @Override // 注解:有功能的注释!
    public void test() {
        System.out.println("A=>test");
    }
}
package com.OOP.demo05;

// 重写都是方法的重写,和属性无关
public class B {
    public void test(){
        System.out.println("B=>test");
    }
}
package com.OOP;

import com.OOP.demo05.A;
import com.OOP.demo05.B;
import com.OOP.demo05.Person;
import com.OOP.demo05.Student;

public class Application {

    // 静态的方法和非静态的方法区别很大!
    // 静态方法:方法的调用只和左边定义的数据类型有关
    public static void main(String[] args) {

        A a = new A();
        a.test();

        // 父类的引用指向了子类
        B b = new A(); // 子类重写了父类的方法
        b.test();
    }
}

注意点:

super 注意点:

  1. super 调用父类的构造方法,必须在构造方法的第一个
  2. super 必须只能出现在子类的方法或者构造方法中!
  3. super 和 this 不能同时调用构造方法!

this :

  • 代表的对象不同
    • this: 本身对象
    • super:代表父类对象的应用
  • 前提
    • this: 没有继承也可以使用
    • super: 只能在继承条件下才可以使用
  • 构造方法
    • this(); 本类的构造
    • super(); 父类的构造!

重写:需要有继承关系,子类重写父类的方法!

  1. 方法名必须相同
  2. 参数类表必须相同
  3. 修饰符:范围可以扩大但不能缩小: public>Protected>Default>private
  4. 抛出的异常:范围,可以被缩小,但不能扩大:ClassNotFoundException --> Exception

重写,子类的方法和父类必须一致:方法体不同!

为什么需要重写:

  • 父类的功能,子类不一定需要,或者不一定满足!

Alt + Insert : override;

多态

  • 即同一个方法可以根据发送对象的不同而采用多种不同的行为方式。

  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多 (父类,有关系的类)

  • 多态存在的条件

    • 有继承关系

    • 子类重写父类方法

    • 父类引用指向子类对象

  • 注意:多态是方法的多态,属性没有多态性。

  • instanceof (类型转换)引用类型

package com.OOP.demo05;

// 在Java中,所有的类,都默认直接或间接继承object
// Person 人 : 父类
public class Person {
    public void run(){
        System.out.println("run");
    }

}
/*
* 多态注意事项
* 1.多态是方法的多态,属性没有多态
* 2.父类和子类,有联系 类型转换异常! ClassCastException!
* 3.存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
*   1. static 方法,属于类,它不属于实例
*   2. final 常量;
*   3. private 方法。
* */

package com.OOP.demo05;

// 学生 is 人:派生类,子类
// 子类继承了父类,就会拥有父类的全部方法!
public class Student extends Person {
    @Override
    public void run() {
        System.out.println("son");
    }
    public void eat(){
        System.out.println("eat");
    }
}

package com.OOP;


import com.OOP.demo05.Person;
import com.OOP.demo05.Student;

public class Application {

    public static void main(String[] args) {
        // 一个对象的实际类型是确定的
        // new Student();
        // new Person();
        // 可以指向的引用类型就不确定了:父类的引用指向子类
        // 子类 能调用的方法是自己的或者继承父类的!
        Student s1 = new Student();
        Person s2 = new Student();
        Object s3 = new Student();

        // 对象能执行哪些方法,主要看对象左边的类型,和右边关系不大!
        s1.run(); // 子类重写了父类的方法,执行了子类的方法
//        s2.run();
//        s2.eat();
    }
}

instanceof和类型转换

package com.OOP.demo05;

public class Person {
    public void run(){
        System.out.println("run");
    }
}
package com.OOP.demo05;

public class Student extends Person{
    public void go(){
        System.out.println("go");
    }

}
package com.OOP.demo05;

public class Teacher extends Person{

}
package com.OOP;


import com.OOP.demo05.Person;
import com.OOP.demo05.Student;
import com.OOP.demo05.Teacher;

public class Application {


    // Object > Person > Student
    // Object > Person > Student
    public static void main(String[] args) {
        /*
        Object object = new Student();
        System.out.println(object instanceof Student); //true
        System.out.println(object instanceof Person); //true
        System.out.println(object instanceof Object); //true
        System.out.println(object instanceof Teacher); //false
        System.out.println(object instanceof String); //false
        System.out.println("======================");
        Person person = new Person();
        System.out.println(person instanceof Student); //false
        System.out.println(person instanceof Person); //true
        System.out.println(person instanceof Object); //true
        System.out.println(person instanceof Teacher); //false
        // System.out.println(person instanceof String); //编译错误
        System.out.println("===========================");
        Student student = new Student();
        System.out.println(student instanceof Student); //true
        System.out.println(student instanceof Person); //true
        System.out.println(student instanceof Object); //true
        //System.out.println(student instanceof Teacher); // 编译报错
        //System.out.println(student instanceof String); // 编译报错
        System.out.println("============================");
        Teacher teacher = new Teacher();
        // System.out.println(teacher instanceof Student); // 编译报错
        System.out.println(teacher instanceof Person); //true
        System.out.println(teacher instanceof Object); //true
        System.out.println(teacher instanceof Teacher); //true
        // System.out.println(teacher instanceof String); // 编译报错
         */

        // 类型之间的转换: 父   子
        Person obj = new Student();

        // 强制类型转换 将 obj 这个对象转换为Student()类型,我们就可以使用Student类型的方法了!
//        Student student = (Student)obj;
//        student.go();
        ((Student)obj).go();

        Student student = new Student();
        student.go();
        // 子类转换为父类,可能会丢失自己本来的一些方法!
        Person person1 = student;
    }
}

/*
* 1.父类应用指向子类
* 2.把子类转换为父类,向上转换;
* 3.把父类转换为子类,向下转换:强制转换
* 4.方便方法的调用,减少重复的代码!简洁
*
* 封装、继承、多态!     抽象类,接口
* */

static

package com.OOP.demo07;

public final class Person {
    // 2 :赋初始值
    {
        System.out.println("匿名代码块");
    }
    // 1 :只执一次
    static{
        System.out.println("静态代码块");
    }
    // 3
    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person = new Person();
        System.out.println("=======================");
        Person person1 = new Person();
    }
}

package com.OOP.demo07;

import com.OOP.demo07.Person;

// static
//public class Student extends Person {  //被final修饰的类无法继承
public class Student {
    private static int age=18; // 静态的变量
    private double score=100;   // 非静态的变量

    public void run(){
        Student.go();
    }
    public static void go(){

    }

    public static void main(String[] args) {
        Student s1 = new Student();

        System.out.println(Student.age);
        System.out.println(s1.age);
        System.out.println(s1.score);

        new Student().run();
        Student.go();

    }
}
package com.OOP.demo07;

// 静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Test {
    public static void main(String[] args) {
        System.out.println(random());
        System.out.println(PI);
    }
}

抽象类

abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。

抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。

抽象类,不能使用new关键字类创建对象,它是用来让子类继承的。

抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。

子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也不要声明为抽象类。

package com.OOP.demo08;
//abstract 抽象类: 类 extends:      单继承~    (接口可以多继承)
public abstract class Action {
    // 约束~有人帮我们实现~
    // abstract , 抽象方法,只有方法名字,没有方法的实现!
    public abstract void dosomething();

    // 1. 不能new这个抽象类,只能靠子类去实现它;约束!
    // 2. 抽象类中可以写普通的方法~
    // 3. 抽象方法必须在抽象类中~
    // 抽象的抽象:约束~
}

package com.OOP.demo08;
// 抽象类的所有方法,继承了它的子类,都必须要实现它的方法~
public class A extends Action{
    @Override
    public void dosomething() {

    }
}

接口

普通类:只有具体实现

抽象类:具体实现和规范(抽象方法)都有!

接口:只有规范!自己无法写方法专业的约束!约束和实现分离:面向接口编程

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是……则 必须能……” 的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑等。

接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、Java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。

声明类的关键字是class,声明接口的关键字是interface

所用:

  1. 约束
  2. 定义一些方法,让不同的人实现~
  3. public abstract
  4. public static final
  5. 接口不能被实例化,接口中没有构造方法
  6. implements 可以实现多个接口
  7. 必须要重写接口中的方法~
package com.OOP.demo09;

// 抽象的思维~ 架构师

// interface 定义的关键字, 接口都需要有实现类
public interface UserService {
    // 常量~ public static final
    int AGE = 99;

    // 接口中的所有定义的方法其实都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
package com.OOP.demo09;

public interface TimeService {
    void time();
}
package com.OOP.demo09;

// 抽象类:extends~
// 类 可以实现接口 implements 接口
// 实现了接口的类,就需要重写接口中的方法~

// 多继承~利用接口实现多继承~
public class UserServiceImpl implements UserService,TimeService {
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void time() {

    }
}

内部类

  • 内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部来了。
  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类
package com.OOP.demo10;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public class Outer {
    private int id=10;
    public void out(){
        System.out.println("这是外部类的方法");
    }
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
        // 获得外部类的私有属性~
        public void getID(){
            System.out.println(id);
        }
    }
}
package com.OOP;

import com.OOP.demo10.Outer;

public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();
        // 通过这个外部类来实例化内部类~
        Outer.Inner inner = outer.new Inner();
        inner.getID();
    }
}

package com.OOP.demo10;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public class Outer {

}

// 一个Java类中可以有多个class类,但只能有一个 public class类
class A{
    public static void main(String[] args) {
        
    }
}

package com.OOP.demo10;


public class Outer {
    // 局部内部类
    public void method(){
        class Inner{
            public void in(){
                
            }
        }
    }
}

package com.OOP.demo10;

public class Test {
    public static void main(String[] args){
        // 没有名字初始化类,不用将实例保存到变量中~
        new Apple().eat();

        UserService userService = new UserService(){
            @Override
            public void hello() {

            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("1");
    }
}

interface UserService{
    void hello();
}

异常机制(Exception)

  1. 什么是异常
  2. 异常体系结构
  3. Java异常处理机制
  4. 处理异常
  5. 自定义异常
  6. 总结

什么是异常

  • 实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等。我们的程序再跑这,内存或硬盘可能满了。等等。
  • 软件程序再运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是:Exception,意思是例外。这些,例外情况,或者叫异常,怎么让我们写的程序做出合理的处理。而不至于程序崩溃。
  • 异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
  • 异常发生在程序运行期间,它不影响正常的程序执行流程。

简单分类

  • 要理解Java异常处理是如何工作的,你需要掌握一下三种类型的异常:
  • 检查行异常:最具代表的检查行异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误ERROR:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译时是检查不到的。

异常体系结构

  • Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
  • 在Java API中已经定义了许多异常类,这些异常类分为两大类,错误ERROR和异常Exception。

image-20220521194452311

Error

  • Error类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无光。
  • Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError.这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止;
  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误时不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。

Exception

  • 在Exception分支中有一个重要的子类RuntimeException(运行时异常)

    • ArrayIndexOutOfBoundsException(数组下标越界)

    • NullPointerException(空指针异常)

    • ArithmeticException(算术异常)

    • MissingResourceException(丢失资源)

    • ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。

  • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;

  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

异常处理机制

  • 抛出异常
  • 捕获异常
  • 异常处理五个关键字
    • try、catch、finally、throw、throws
package com.OOP.exception;

public class Test {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        try{
          System.out.println(a/b);
        }catch (ArithmeticException e){
            System.out.println("程序出现异常,常量b不能为0");
        }finally {
            System.out.println("finally");
        }
    }
}

package com.OOP.exception;

public class Test {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        // 假设要捕获多个异常:从小到大的捕获。
        try{ // try监控区域
            // new Test().a();
          System.out.println(a/b);
        }catch (Error e){ // catch,想要捕获的异常类型!
            System.out.println("Error");
        }catch(Exception e){
            System.out.println("Exception");
        }catch (Throwable t){
            System.out.println("Throwable");
        }finally { // 处理善后工作,可以不要finally,一般用于IO,资源,关闭!
            System.out.println("finally");
        }
    }
    public void a(){
        b();
    }
    public void b(){
        a();
    }
}
package com.OOP.exception;

public class Test2 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        // Ctrl + Alt + T 自动生成 try{},catch(){},finally{} 代码块
        try {
            System.out.println(a/b);
        } catch (Exception e) {
            System.exit(1);
            e.printStackTrace(); // 打印错误的栈信息。
        } finally {
        }
    }
}

package com.OOP.exception;

public class Test {
    public static void main(String[] args) {
        new Test().test(1,0);
    }

    public void test(int a ,int b){
        if (b==0){
            throw new ArithmeticException();// 主动抛出异常,一般在方法中使用
        }
    }
}

package com.OOP.exception;

public class Test {
    public static void main(String[] args) {
        try {
            new Test().test(1,0);
        } catch (ArithmeticException e) {
            System.out.println("b不能为零");
            e.printStackTrace();
        } finally {
        }
    }

    // 假设这个方法中,处理不了这个异常。方法上抛出异常。在方法上抛出,要在调用这个方法的方法体中捕获或者继续向上抛出。
    public void test(int a ,int b) throws ArithmeticException{
        if(b==0){
            throw new ArithmeticException();// 主动抛出异常,一般在方法中使用
        }
        System.out.println(a/b);
    }
}

自定义异常

使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。

在程序中使用自定义异常类,大体可分为一下几个步骤:

  1. 创建自定义异常类。
  2. 在方法中通过throw关键字抛出异常对象。
  3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  4. 在出现异常方法的调用者中捕获并处理异常。
package com.OOP.exception.demo02;

// 继承了Exception类后便是自定义异常类。
public class MyException extends Exception {
    // 传递数字>10;
    private int detail;

    public MyException(int a) {
        this.detail = a;
    }
    // toString:异常的打印信息

    @Override
    public String toString() {
        return "MyException{" + detail +'}';
    }
}

package com.OOP.exception.demo02;

public class Test {
    // 可能会存在异常的方法
    static void test(int a) throws MyException{
        System.out.println("传递的参数为:"+a);
        if (a>10){
            throw new MyException(a); // 抛出
        }
        System.out.println("OK");
    }

    public static void main(String[] args) {
        try {
            test(11);
        } catch (MyException e) {
            //在这里可以增加一些处理异常的代码
            System.out.println("MyException==>"+e);
        }
    }
}

实际应用中的经验总结

  • 处理运行时异常时,采用逻辑去合理规避同时辅助 try-catch 处理
  • 在多重 catch 块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
  • 对于不确定的代码,也可以加上try-catch,处理潜在的异常
  • 尽量去处理异常,切记只是简单地调用 printStackTrace() 去打印输出
  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  • 尽量添加finally语句块去释放占用的资源
posted @   房东家的猫  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示