Java基础语法

1、Java基础

1.1、注释

  • 平时我们编写代码,在代码量比较少的时候,我们还可以看懂自己写的,但是当项目结构一旦复杂起来,我们就需要用到注释了。
  • 注释并不会被执行,是给我们写代码的人看的
  • 书写注释是一个非常好的习惯

Java中的注释有三种:

  1. 单行注释 用法:// 输入内容

    image-20220605132837719

  2. 多行注释 用法:/* 输入内容 */

image-20220605133156504

​ 3.文档注释 用法:/** 输入内容 */

image-20220605133708501

1.2、标识符

Java所有的组成部分都需要名字。类名、变量名以及方法名都被成为标识符。

关键字

image-20220605134253446

注意事项

  • 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始

  • 首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或数字的任何字符组合

  • 不能使用关键字作为变量名或方法名

  • 标识符是大小写敏感的

  • 合法标识符举例:age、$salary、_value、__1_value

  • 非法标识符举例:123abc、-salary、#abc

image-20220605135359158

1.3、数据类型

强类型语言

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

错误示范:

image-20220605141510550

正确示范:

image-20220605141820497

image-20220605141843002

Java的数据类型分为两大类

  • 基本类型(primitive type)
  • 引用类型(reference type)

image-20220605142112756

image-20220605143900903

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

        //八大数据类型

        //整数
        byte num1 = 10;     //最常用
        short num2 = 20;
        int num3 = 30;
        long num4 = 40L;    //Long类型要在数字后面加个L

        //小数:浮点数
        float num5 = 80.1F;     //float类型要在数字后面加个F
        double num6 = 2.13;

        //字符
        char name1 = 'A';
        //字符串,String 不是关键字
        //String name2 = "chenxin";

        //布尔值:是非
        boolean flag1 = true;
        boolean flag2 = false;
        
    }
}

什么是字节

  • 位(bit):是计算机内部数据储存的最小单位,11001100是一个八位二进制数。
  • 字节(byte):是计算机中数据处理的基本单位,习惯上用大写B来表示。
  • 1B(byte,字节)= 8bit(位)
  • 字符:是指计算机中使用的字母、数字、字和符号

扩展面试题

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

        //整数拓展: 进制  二进制0b   十进制     八进制0    十六进制0x

        int i1 = 10;
        int i2= 010;    //八进制0
        int i3 = 0x10;    //十六进制0x  0~9 A~F 16

        System.out.println(i1);
        System.out.println(i2);
        System.out.println(i3);

        System.out.println("==========================");

        //浮点数拓展     有限 离散 舍入误差 大约   接近但不等于
        //最好完全避免使用浮点数进行比较

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

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

        float d1 = 22412412421414214f;
        float d2 = 1+d1;
        System.out.println(d1==d2); //true

        System.out.println("==========================");

        //字符拓展
        //所有的字符本质还是数字
        //编码 Unicode 表:97=a    65=A
        char c1 = '中';
        char c2 = 'a';

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

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


        //  U0000   UFFFF
        char c3 = '\u0061';

        System.out.println(c3);     //a

        System.out.println("==========================");

        //转义字符
        //  \t  制表符
        System.out.println("Hello\tWorld");

        //  \n  换行
        System.out.println("Hello\nWorld");

    }
}

image-20220605154058111

1.4、类型转换

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

低------------------------------------------------------------------>高

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

  • 运算中,不同类型的数据先转换为同一类型,然后进行运算。

    public class HelloWorld {
        public static void main(String[] args) {
    
            //强制转换  (类型)变量名 高-->低
            int i = 128;
            byte b = (byte)i;
    
            System.out.println(i);
            System.out.println(b);
    
            System.out.println("======================================");
    
            //自动转换  低-->高
            int a = 128;
            double c = a;
    
            System.out.println(a);
            System.out.println(c);
            
            System.out.println("======================================");
    
            System.out.println((int)16.8);
            System.out.println((int)-45.89f);
        }
    }
    
    

    image-20220605161805255

注意事项:

  1. 不能对布尔值进行转换
  2. 不能把对象类型转换为不相干的类型
  3. 在把高容量转换到低容量的时候,强制转换
  4. 转换的时候,可能存在内存内存溢出,或者精度问题!

1.5、变量、常量、作用域

变量

  • 变量是什么:就是可以变化的量!
  • Java是一种强类型语言,每个变量都必须声明其类型。
  • Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
	type varChar [=value] [{,varName[=value]}];
	//数据类型 变量名=值;可以使用逗号隔开来声明多个同类型变量。

注意事项

  • 每个变量都有类型,类型可以是基本类型,也可以是引用类型。
  • 变量名必须是合法的标识符。
  • 变量声明是一条完整的语句,因此每一个声明都必须以分号结束。

常量

  • 常量:初始化后不能再改变值!不会变动的值。
  • 所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。
  • 常量名一般使用大写字符。
	static final 常量名=值;
    static final double PI=3.14;	
public class HelloWorld {
    //修饰符,不存在先后顺序
    static final double PI=3.14;
    public static void main(String[] args) {

        System.out.println(PI);


    }
}

image-20220605172106405

变量的命名规范

  • 所有变量、方法、类名:见名知意
  • 类成员变量:首字母小写和驼峰原则:monthSalary
  • 局部变量:首字母小写和驼峰原则
  • 常量:大写字母和下划线:MAX_VALUE
  • 类名:首字母大写和驼峰原则:Man,GoodMan
  • 方法名:首字母小写和驼峰原则:run(),runRun()

变量作用域

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

1.6、基本运算符

Java语言支持的运算符

  • 算数运算符:+ - * / % ++ --
  • 赋值运算符:=
  • 关系运算符:> < >= <= == !=instanceof
  • 逻辑运算符:&& || !
  • 位运算符:& | ^ ~ >> << >>>
  • 条件运算符:?:
  • 扩展赋值运算符:+= -= *= /=

image-20220605174804247

演示1

public class HelloWorld {

    public static void main(String[] args) {

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


        System.out.println(a+b);
        System.out.println(a-b);
        System.out.println(a*b);
        System.out.println((double)a/b);
    }
}

image-20220605180222915

演示2

public class HelloWorld {

    public static void main(String[] args) {

        long a = 21387129373213173L;
        int b = 240;
        int c = 10;
        int d = 2;


        //没有Long时,所有非Int类型转为Int类型
        System.out.println(a+b+c+d);	//Long
        System.out.println(b+c+d);		//Int
        System.out.println(c+d);		//Int

    }
}

image-20220605180547800

演示3

public class HelloWorld {

    public static void main(String[] args) {

        //关系运算符返回的结果:正确,错误  布尔值
        long a = 10;
        int b = 20;

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

    }
}

image-20220605181144315

1.7、自增自减运算符

演示1

public class HelloWorld {

    public static void main(String[] args) {

        //++  --  自增,自减  一元运算符

        int a = 3;

        int b = a++;    //执行完这行代码后,先给b赋值,再自增

        //  a = a+1
        System.out.println(a);

        //  a++ a = a+1;


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


    }
}

image-20220605194735300

原理

a b
b=a++ 4 3

b=a++ 先给b赋值,再自增1

演示2

public class HelloWorld {

    public static void main(String[] args) {

        //++  --  自增,自减  一元运算符

        int a = 3;

        int b = a++;    //执行完这行代码后,先给b赋值,再自增

        //  a = a+1
        System.out.println(a);

        //  a++ a = a+1;
        int c = ++a;    //执行完这行代码后,先自增,再给c赋值

        System.out.println(a);
        System.out.println(b);
        System.out.println(c);

    }
}

image-20220605194819742

a b c
b=a++ 4 3
c=++a 5 5

b=a++ 先给b赋值,a再自增1

c=++a a先自增1,再给c赋值,b不变

1.8、逻辑运算符、位运算符

逻辑运算符

public class HelloWorld {

    //逻辑运算符
    public static void main(String[] args) {

        //  与(and)  或(or)   非(取反)
        boolean a = true;
        boolean b = false;

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

image-20220605202857998

原理

&& 与运算 有假为假

|| 或运算 有真为真

非运算 假为真 真为假

异或运算 同号为真 异号为假

短路运算

public class HelloWorld {


    public static void main(String[] args) {

        //短路
        int a = 3;
        boolean b = (a<1)&&(a++<2);

        System.out.println(a);
        System.out.println(b);
    }
}

image-20220605204018940

原理

a=3时,不小于1,则(a<1)是false,第一项为false则短路,后面的a++不会被执行,那么输出还是3,
如果第一项为true,那么继续第二步的运算,输出为4。

我们来测试一下

public class HelloWorld {


    public static void main(String[] args) {

        int a = 3;
        boolean b = (a<10)&&(a++<2);

        System.out.println(a);
        System.out.println(b);
    }
}

image-20220605204425870

位运算符

常量 数值
A 0011 1100
B 0000 1101
A&B 0000 1100 (有0说0)
A|B 0011 1101 (有1说1)
A^B 0011 0001 (异或:相同为0,相异为1)
~B 1111 0010 (取反)

<< 和 >>

public class HelloWorld {


    public static void main(String[] args) {

        /*
        0000	0000		0
        0000	0001		1
        0000	0010		2
        0000	0100		4
        0000	1000		8
        0001	0000		16

        2*8 = 16 2*2*2*2 = 16
        <<  *2
        >>  /2
        */

        System.out.println(2<<3);
    }
} 

image-20220605210627541

+= 和 -=

public class HelloWorld {


    public static void main(String[] args) {


        int a = 10;
        int b = 20;

        a+=b;

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

        System.out.println("===========================================");

        int c = 10;
        int d = 20;

        c-=d;

        System.out.println(c);
        System.out.println(d);
    }
}

image-20220605211425321

字符串连接符

public class HelloWorld {


    public static void main(String[] args) {

        //  字符串连接符 + ,String
        int a = 10;
        int b = 20;

        System.out.println(""+a+b);
        System.out.println(a+b+"");
    }
}

image-20220605211855986

1.9、三元运算符

public class HelloWorld {

    public static void main(String[] args) {

        //  x   ?   y   :   z
        //  如果x=true,则结果为y,否则结果为z

        int score = 90;
        String type = score<60 ?"不及格":"及格";

        System.out.println(type);

    }
}

image-20220605212823373

1.10、包机制

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

  • 包语句的语法格式为:

    package pkg1[. pkg2[. pkg3..]];
    
  • 一般利用公司域名倒置作为包名;例:com.baidu.www

  • 为了能使用某一个包的成员,我们需要在Java程序中明确导入该包。使用”import“语句可完成此功能。

    import package1[.package2..].(classmate*);
    

1.11、JavaDoc生成文档

  • javadoc命令是用来生成自己的API文档的
  • 参数信息
    • @author 作者名
    • @version 版本号
    • @since 指明需要最早使用的jdk版本
    • @param 参数名
    • @return 返回值情况
    • @throws 异常抛出情况
/**
 * @author chenxin
 * @version 1.0
 * @since 1.8
 */
public class HelloWorld {

    String name;
    
    public String test(String name){
        return name;
    }
}

使用idea生成javadoc

在顶部工具栏中,tool里generate JavaDoc,如下配置

image-20220605221015701

image-20220605221056496

2、Java流程控制

2.1、用户交互Scanner

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

  • 基本语法:

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

Scanner对象

  • next():

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

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

演示1

import java.util.Scanner;

public class HelloWorld {

    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();
    }

    }

image-20220606091414878

演示2

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //创建一个扫描器对象,用于接收键盘数据
        Scanner scanner = new Scanner(System.in);

        System.out.println("使用next方式接收:");

        //判断用户有没有输入字符串
        if (scanner.hasNext()){
            //  使用next方式接收
            String str = scanner.nextLine();
            System.out.println("输入的内容为:"+str);

        }

        //凡是属于IO流的类如果不关闭会一直占用资源,要养成良好习惯用完就关
        scanner.close();
    }

}

image-20220606091833861

演示3

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

            //创建一个扫描器对象,用于接收键盘数据
            Scanner scanner = new Scanner(System.in);

            System.out.println("使用next方式接收:");

            //  使用next方式接收
            String str = scanner.nextLine();
            System.out.println("输入的内容为:"+str);

            //凡是属于IO流的类如果不关闭会一直占用资源,要养成良好习惯用完就关
            scanner.close();
    }

}

image-20220606092958061

2.2、Scanner进阶使用

演示1

import java.util.Scanner;

public class demo1 {

    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();
    }

}

image-20220606094149683

image-20220606094422314

演示2

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入输出执行结果:
        Scanner scanner = new Scanner(System.in);

        //和
        double sum = 0;

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

        System.out.println("请输入数据:");
        //通过循环判断是否还有输入,并在里面对每一次进行求和统计
        while (scanner.hasNextDouble()){
            double v = scanner.nextDouble();

            m = m+1;    //m++
            sum = sum +v;
            System.out.println("你输入了"+m+"个数据,当前sum="+sum);
        }


        System.out.println(m+"个数的和为"+sum);
        System.out.println(m+"个数的平均值为"+(sum/m));

        scanner.close();
    }

}

image-20220606100224983

2.3、顺序结构

  • Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。
  • 顺序是最简单的算法结构。
  • 语句和语句直接,框和框之间是按照从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。

image-20220606101658321

演示

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        System.out.println("Hello World1");
        System.out.println("Hello World2");
        System.out.println("Hello World3");
        System.out.println("Hello World4");
        System.out.println("Hello World5");
    }

}

image-20220606102018171

2.4、选择结构

if选择结构

  • if单选择结构

    1. 我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用if语句来表示

    2. 语法:

      if(布尔表达式){
          //如果布尔表达式为true将执行的语句
      }
      

      image-20220606102711443

演示

import java.util.Scanner;

public class demo1 {

    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();

    }

}

image-20220606104248146

image-20220606104340488

  • if双选择结构

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

    2. 语法:

      if(布尔表达式){
          //如果布尔表达式的值为true
      }else{
          //如果布尔表达式的值为false
      }
      

      image-20220606161009157

演示

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //考试分数大于等于60分为及格,考试分数小于60分为不及格
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入成绩:");

        int score = scanner.nextInt();

        //双循环
        if(score>=60){
            System.out.println("及格");
        }else{
            System.out.println("不及格");
        }
        
        scanner.close();
    }

}

image-20220606162657094

image-20220606162713727

  • if多选择结构

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

    2. if语句至多有1个else语句,else语句在所有的else if语句之后。
      if语句可以有若干个else if 语句,它们必须在else语句之前。
      一旦其中一个else if 语句检测为true,其他的else if 以及else语句都将跳过执行。

    3. 语法

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

      image-20220606163211826

演示

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //考试分数90-100,考核结果为A
        //考试分数80-89,考核结果为B
        //考试分数70-79,考核结果为A
        //考试分数60-69,考核结果为D
        //考试分数<60,考核结果为不合格
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入成绩:");

        int score = scanner.nextInt();

        //多循环
        if(score>=90 && score<=100){
            System.out.println("A");
        }else  if(score>=80 && score<=89){
            System.out.println("B");
        }else  if(score>=70 && score<=79){
            System.out.println("C");
        }else  if(score>=60 && score<=69){
            System.out.println("D");
        }else  if( score<60){
            System.out.println("不合格!");
        }else{
            System.out.println("请输入有效的成绩!");
        }


        scanner.close();
    }

}

image-20220606164422497

image-20220606164635767

image-20220606164944877

Swith选择结构

  • 多选择结构还有一个实现方式就是switch case语句。

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

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

    • byte、short、int或者char
    • 从Java SE 7开始
    • switch支持字符串String类型了
    • 同时case标签必须为字符串常量或字面量
  • 语法

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

演示

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入一个A——D之间的等级:");

        String grade = scanner.nextLine();


        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;
            default:
                System.out.println("未知!");
        }


        scanner.close();
    }

}

image-20220606172614230

image-20220606172628539

2.5、循环结构

While循环

  • while是最基本的循环,它的结构为

    while(布尔表达式){
        //循环内容
    }
    
  • 只要布尔表达式为true,循环就会一直执行下去

  • 我们大多数情况下是会让循环停止下来的,我们需要一个让表达式失效的方式来结束循环

  • 少部分情况需要循环一直执行,比如服务器的请求响应监听等

  • 循环条件一直为true就会造成无限循环【死循环】,我们正常的业务编程中应该尽量避免死循环。会影响程序性能或者造成程序卡死崩溃!

image-20220606185418109

演示:输出1-100

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {


        //输出1-100

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

}

image-20220606184346524

演示:计算1+2+3+4+·······+100

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //1+2+3+4+······+100

        int i = 0;
        int sum = 0;

        while (i<=100){
            sum = sum+i;
            i++;

        }
        System.out.println(sum);
    }

}

image-20220606185051190

原理

image-20220606185351912

DoWhile循环

  • 对于while语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次

  • do...while循环和while循环相似,不同的是,do...while循环至少会执行一次

  • while和do-while的区别:

    1. while先判断后执行,dowhile是先执行后判断!
    2. do...while总是保证循环体会被至少执行一次!这是他们的主要差别。
  • 语法:

    do{
        //代码语句
    }while(布尔表达式);
    

演示

import java.util.Scanner;

public class demo1 {

    public static void main(String[] args) {

        //1+2+3+4+······+100

        int i = 0;
        int sum = 0;

        do{
            sum = sum+i;
            i++;
        }while (i<=100);

        System.out.println(sum);
    }

}

image-20220606191841739

演示:while和dowhile的区别

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {

        int a = 0;

        //while循环
        while(a<0){
            a++;
            System.out.println(a);
        }

        System.out.println("=====================================");

        //dowhile循环
        do{
            System.out.println(a);
            a++;
        }while (a<=0);

    }
}

image-20220606192508084

For循环

  • 虽然所有循环结构都可以用while或者do...while表示,但java提供了另一种语句——for循环,使一些循环结构变得更加简单

  • for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构

  • for循环执行的次数是在执行前就确定的。语法格式如下:

    for(初始化;布尔表达式;更新){
        //代码语句
    }
    

演示:while和for的区别

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {
        //while循环
        int a = 1;              //初始化条件

        while(a<=100){          //条件判断
            a+= 2;              //迭代
            System.out.println(a);
        }

        System.out.println("while循环结束!");

        //for循环		快捷键 100.for
        for(int i = 1;i <= 100;i++){          //初始化条件;条件判断;迭代
            System.out.println(i);
        }

        System.out.println("for循环结束!");
        
    }
}

image-20220606194325234

注意事项

  • 最先执行初始化步骤,可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句
  • 然后,检测布尔值表达式的值。如果为true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句
  • 执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)
  • 再次检测布尔表达式。循环执行上面的过程

练习1:计算0到100之间的奇数和偶数的和

import java.util.Scanner;
public class demo1 {
    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;
            }else{
                evensum+=i;
            }
        }

        System.out.println("奇数和为:"+oddsum);
        System.out.println("奇数和为:"+evensum);
    }
}

练习2:用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {

        //练习2:用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个
        for (int i = 1; i <=1000; i++) {
            if(i%5==0){
                System.out.print(i+"\t");   //输出一行,\t是输出之间有间隔
            }

            if(i%(5*3)==0){
                System.out.println();       //每行输出三个
                //System.out.print("\n");       //每行输出三个

            }

        }
    }
}

image-20220606203913335

注意:

1.println 输出完会换行

2.print 输出完不会换行

2.6、打印九九乘法表

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {

        for (int j = 1; j <= 9; j++) {

            for (int i = 1; i <= j; i++) {      //避免重复的乘积,那么i<=j
                System.out.print(i+"*"+j +"="+(j*i) + "\t" );   // “\t”表示table的意思,空格!
            }
            System.out.println();                    //在每执行完一列之后,换列
        }

    }
}

image-20220606212934967

2.7、增强for循环

  • Java5引入了一种主要用于数组或集合的增强型for循环

  • Java增强for循环语法格式如下:

    for(声明语句:表达式)
    {
        //代码句子
    }
    
  • 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等

  • 表达式:表达式是要访问的数组名,或者是返回值为数组的方法

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {

       int[] num = {1,2,3,4,5,6,7,8}; //定义了一个数组


        //增强for循环
        for (int i = 0; i < 8; i++) {
            System.out.println(num[i]);
        }

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

    }
}

image-20220606214714166

2.8、break、continue、goto

  • break:break在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。
    (break语句也在switch语句中使用)
  • continue:continue语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
  • goto:
    1. goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但并未在语言中得到正式使用;Java没有goto。然而,在break和continue这两个关键字上,我们仍然能看出一些goto的影子--带标签的break和continue。
    2. “标签”是指后面跟一个冒号的标识符,例如:label:
    3. 对Java来说唯一用到标签的地方是在循环语句之前。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {


        int i = 0;
        while (i<100) {
            i++;
            if (i % 10 == 0) {
                System.out.println();
                continue;		//终止某次循环
            }
            System.out.print(i+"\t");
        }
    }
}

image-20220606221126065

2.9、打印三角形

import java.util.Scanner;
public class demo1 {
    public static void main(String[] args) {
        //打印三角形

        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();


        }
    }
}

image-20220606224419536

3、Java方法

3.1、方法

  • Java方法是语句的集合,它们在一起执行一个功能
    • 方法是解决一类问题的步骤的有序组合
    • 方法包含于类或对象中
    • 方法在程序中被创建,在其他地方被引用
  • 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只能完成一个功能,这样利于我们后期的扩展
public class demo1 {
    public static void main(String[] args) {
        //实际参数:实际调用传递给他的参数
        int sum = add(1, 2);	//调用方法
        System.out.println(sum);

    }

    //形式参数,用来定义作用的
        public static int add(int a,int b){		//方法
            return a+b;

    }
}

image-20220607093301867

3.2、方法的定义和调用

定义

  • Java的方法类似于其它语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:

    修饰符		返回值类型	方法名(参数类型 参数名){
       		...
            方法体
            ...
            return 返回值;
    }		
    
  • 方法包含一个方法头和一个方法体。下面是一个方法的所有部分:

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

调用

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

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

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

    int larger = max(30,40);
    
  • 如果方法返回值是void,方法调用一定是一条语句。

    System.out.println("Hello,chenxin!")
    

演示

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

        int max = max(10, 20);
        System.out.println(max);


    }
    public static int max(int num1,int num2){

        int result;
        if(num1==num2){
            System.out.println("num1==num2");
            return 0;
        }
        if(num1>num2){
            result=num1;
        }else{
            result=num2;
        }
        return result;

    }


}

image-20220607101124878

3.3、方法的重载

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

        int max = max(10, 20);
        System.out.println(max);

    }
    //定义了int类型的方法
    public static int max(int num1,int num2){

        int result;
        if(num1==num2){
            System.out.println("num1==num2");
            return 0;
        }
        if(num1>num2){
            result=num1;
        }else{
            result=num2;
        }
        return result;

    }

	//定义了double类型的方法
    public static double max(double num1,double num2){

        double result;
        if(num1==num2){
            System.out.println("num1==num2");
            return 0;
        }
        if(num1>num2){
            result=num1;
        }else{
            result=num2;
        }
        return result;

    }
}

image-20220607103225797

3.4、可变参数

  • JDK 1.5开始,Java支持传递同类型的可变参数给一个方法。
  • 在方法声明中,在指定参数类型后加一个省略号(.…)。
  • 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
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( "The max value is " + result);
}           

演示

public class demo1 {
    public static void main(String[] args) {
        demo1 demo1 = new demo1();
        demo1.test(1,2,3,4,5,6);
    }
    public static void test(int...i){

        System.out.println(i[3]);
    }
}

image-20220607110251113

3.5、递归

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

演示:阶乘

public class demo1 {
    public static void main(String[] args) {
        System.out.println(f(3));

    }
    public static int f(int n){
        if(n==1){
            return 1;
        }else{
            return n*f(n-1);
        }

    }
}

image-20220607113332660

image-20220607113350032

原理图

image-20220607114314197

image-20220607114453338

4、Java数组

4.1、数组

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

image-20220607145713576

4.2、数组的声明和创建

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

    dataType[] arrayRefVar;	//首选的方法
    dataType arrayRefVar[]; // 效果相同,但不是首选方法
    
  • Java语言使用new操作符来创建数组,语法如下:

    dataType[] arrayRefVar = new dataType[arraySize];
    
  • 数组的元素是通过索引访问的,数组索引从0开始。

  • 获取数组长度:

    arrays.length
    
public class demo1 {
    public static void main(String[] args) {


        int[] nums; //声明了一个数组

         nums = new int[10];//2.创建了一个数组,这里可以存放10个int类型的数字

        //3.给数组中的元素赋值
        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;

        System.out.println(nums[7]);

    }
}

image-20220607174724890

原理图:

image-20220607173408528

演示:计算十个数的和

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


        int[] nums; //1.声明了一个数组

         nums = new int[10];//2.创建了一个数组,这里可以存放10个int类型的数字

        // int[] nums = new int[10];    也可以这么写,声明并创建

        //3.给数组中的元素赋值
        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 = sum + nums[i];
            
        }
        System.out.println("总和为:"+sum);

    }
}

image-20220607175741108

4.3、内存分析及三种初始化

Java内存分析

image-20220607175956892

image-20220607200439245

三种初始化

  • 静态初始化
int[] a = {1,2,3};
Man[] mans = {new Man(1,1),new Man(2,2)};
  • 动态初始化
int[] a = new int[2];
a[0]=1;
a[1]=2;
  • 数组的默认初始化
    • 数组是引用类型,它的元素相当于类的实例变量,因此数组- -经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。

演示

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

        //静态初始化:创建+赋值
        int[] a = {1,2,3,4,5};
        System.out.println(a[3]);

        System.out.println("======================");

        //动态初始化:包含默认初始化,默认值为0,初始化之后被赋值
        int[] b= new int[5];
        
        b[0] = 6;
        b[1] = 7;
        b[2] = 8;
        b[3] = 9;
        b[4] = 10;

        System.out.println(b[3]);

        System.out.println("======================");


    }
}

image-20220607201829423

4.4、数组的基本特点和下标越界

四个基本特点

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

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

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

  • 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
    数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,
    数组对象本身是在堆中的。

下标越界

  • 下标的合法区间: [0, length-1],如果越界就会报错;
public static void main(String[] args) {
    int[ ] a=new int[2];
    System. out . println(a[2]);
}
  • ArrayIndexOutOfBoundsException :数组下标越界异常!
  • 小结:
    • 数组是相同数据类型(数据类型可以为任意类型)的有序集合
    • 数组也是对象。数组元素相当于对象的成员变量
    • 数组长度的确定的,不可变的。如果越界,则报: ArrayIndexOutofBounds

演示

public class demo1 {
    public static void main(String[] args) {
        
        int[] a = {1,2,3,4,5,6,7,8};

        for (int i = 0; i < a.length; i++) {	//<可以遍历所有元素,加了=会下标越界
            System.out.println(a[i]);
            
        }

    }
}

image-20220607203407681

4.5、数组的使用

  • For-Each循环
  • 数组作方法入参
  • 数组作返回值

演示: for循环

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

        int[] a = {1,2,3,4,5,6,7,8};

        //输出所有的数组元素
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
        System.out.println("===========================");

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

        System.out.println("===========================");

        //查找最大元素
        int max = a[0];

        for (int i = 1; i < a.length; i++) {
            if(a[i] > max){
                max = a[i];
            }
        }

        System.out.println("最大的数为:"+max);
    }
}

image-20220607204920933

演示:For-Each循环

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

    int a[] = {1,2,3,4,5,6};

        for (int i : a) {
            System.out.println(i);
        }
    }
}

image-20220607205915458

4.6、多维数组

  • 多维数组可以看成数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组
  • 二维数组
int a[][] = new int[2][5];
  • 解析:以上二维数组a可以看成一个两行五列的数组

image-20220607211506482

image-20220607211816326

演示:输出二维数组中的其中一个数组

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


        //[4][2]
        /*
            1,2     array[0]
            3,4     array[1]
            5,6     array[2]
            7,8     array[3]
         */

        int[][] array = {{1,2},{3,4},{5,6},{7,8}};
        System.out.println(array[2][0]);
        System.out.println(array[2][1]);

        }

    }

image-20220607214043958

演示:输出二维数组里的所有元素

public class demo1 {
    public static void main(String[] args) {
        
        //[4][2]
        /*
            1,2     array[0]
            3,4     array[1]
            5,6     array[2]
            7,8     array[3]
         */

        int[][] array = {{1,2},{3,4},{5,6},{7,8}};
        for (int i = 0; i < array.length; i++) {        //外面数组,长度为4
            for (int j = 0; j < array[i].length; j++) {     //里面数组
                System.out.println(array[i][j]);
            }
            
        }
        
        }

    }

image-20220607215053473

4.7、Arrays类

  • 数组的工具类java.util.Arrays
  • 由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作
  • 查看JDK帮助文档。
  • Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而“不用”使用对象来调用(注意:是“不用”而不是“不能”)
  • 具有以下常用功能:
    • 给数组赋值:通过fill方法。
    • 对数组排序:通过sort方法,按升序。
    • 比较数组:通过equals方法比较数组中元素值是否相等。
    • 查找数组元素:通过binarySearch方法对排序好的数组进行二分查找法操作。

演示:两种方法输出数组

import java.util.Arrays;

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

        int[] a = {213,435,853,9621321,124444};

        //方式1:输出数组元素Arrays.toString(用工具类来输出)
        System.out.println(Arrays.toString(a));

        //调用之前写的方法
        printArray(a);
        }


        //方式:2:调用方法来输出
    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]+", ");
            }

        }
    }
    }

image-20220608090731413

演示:对数组进行排序

import java.util.Arrays;

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

        int[] a = {213,435,853,9621321,124444};

        //对数组进行排序,升序
        Arrays.sort(a);

        //输出数组
        System.out.println(Arrays.toString(a));

    }
 }

image-20220608091117258

4.8、冒泡排序

  • “冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。”
  • 冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人皆知。
  • 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为 O(n2)
  • 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序算法:
    1. 直接插入排序
    2. 希尔排序
    3. 简单选择排序
    4. 堆排序
    5. 冒泡排序
    6. 快速排序
    7. 归并排序
    8. 桶排序/基数排序

原理图

image-20220608092014751

image-20220608092054592

image-20220608093801325

交换两个变量的值

1.t = b 把b赋值给t ,b此时为空

2.b = a 把a赋值给b,a此时为空

3.a = t 把t赋值给a, t此时为空

演示:冒泡排序

import java.util.Arrays;

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

        int[] a ={21,56,5,9,2,982,452,67,12,444};

        int[] sort = sort(a);//调用方法,返回排序后的数字

        System.out.println(Arrays.toString(sort));  //  输出

    }

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

    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++) {    //-i是因为,第i次比较之后,已经产生了i个最大或最小的数,不需要进行下一轮的比较了
                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;
    }

}

image-20220608100950699

4.9、稀疏数组

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

    image-20220608121423496

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

  • 解决:稀疏数组

定义:

  • 当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。
  • 稀疏数组的处理方式是:
    • 记录数组一共有几行几列,有多少个不同值
    • 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
  • 如下图:左边是原始数组,右边是稀疏数组

image-20220608121209368

演示:二维数组-->稀疏数组 稀疏数组-->二维数组

public class demo1 {
    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();
        }

        System.out.println("===========================");

        //转换为稀疏数组保存
        //1.获取有效值的个数
        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];
                }
            }
        }

        //3.输出稀疏数组
        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 : array3) {     //输出一维数组
            for (int anInt : ints) {    //输出二维数组
                System.out.print(anInt+"\t");
            }
            System.out.println();
        }
    }

}

image-20220608135259163

image-20220608135309302

5、Java面向对象

5.1、面向对象

面向对象和面向过程的区别

  • 面向过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么......
    • 面向过程适合处理一些较为简单的问题
  • 面向对象思想
    • 物以聚类,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
  • 对于描述复杂的事务,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
  • 抽象
  • 三大特性:
    • 封装
    • 继承
    • 多态
  • 从认识角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
  • 从代码运行角度考虑是现有类后有对象。类是对象的模板。

5.2、回顾方法的定义和调用

  • 方法的定义
    • 修饰符
    • 返回类型
    • break和return的区别
    • 方法名
    • 参数列表
    • 异常抛出

演示:各种方法的声明

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


        }
    /*
       修饰符 返回值类型 方法名(。。。){
       //方法体
       return 返回值;
       }
        */
    //return 结束方法,返回一个结果!
    public String sayHello(){
        return "Hello,world!";
    }

    public void a(){
        return;
    }

    public int max(int a ,int b){
        return a > b ? a : b;    //如果a>b,那么结果为a,否则结果为b
    }
}
  • 方法的调用
    • 静态方法
    • 非静态方法
    • 形参和实参
    • 值传递和引用传递
    • this关键字

演示:静态方法,可以直接调用

Student.java

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

}

demo1.java

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

        Student.say();
    }
}

image-20220608154916135

演示:非静态方法,不可以直接调用,需要new

Student.java

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

}

demo1.java

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

        //实例化这个类,new
        //对象类型 对象名 = 对象值
        Student student = new Student();

        student.say();
    }
}

image-20220608155425530

值传递

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

       int a = 1;
        System.out.println(a);

        demo1.change(a);
        System.out.println(a);		//返回值依旧为1
    }
    public static  void change(int a){
        a = 10;
    }
}

image-20220608160736777

引用传递

public class demo1 {
    public static void main(String[] args) {
        Person person = new Person();

        System.out.println(person.name);//null

        demo1.change(person);

        System.out.println(person.name);//陈鑫
        
    }
    public static void change(Person person){
        //person是一个对象:指向的 ---> Person person = new Person();这是一个具体的人,可以改变属性!
        person.name = "陈鑫";
    }
}

//定义了一个Person类,有一个属性
class Person{
    String name;
}

image-20220608162050333

5.3、类与对象的关系

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

image-20220609082255218

image-20220609082303954

5.4、类与对象的创建

  • 使用new关键字创建对象

  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行潜移默化的初始化以及对类中构造器的调用。

Student.java

//学生类
public class Student {

    //属性:字段
    String name;
    int age;

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

}

demo1.java

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

        Student student = new Student();

        student.name = "陈鑫";
        student.age = 22;

        System.out.println("学生姓名为:"+student.name);
        System.out.println("学生年龄为:"+student.age);
    }
}

image-20220609084236415

5.5、构造器

类中的构造器也成为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点

  • 必须和类的名字相同
  • 必须没有返回类型,也不能写void

Student.java

//学生类
public class Student {

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

    //实例化初始值
    //1.使用new关键字,本质是在调用构造器,此处为无参构造
    //2.用来初始化值
    public Student(){
        this.name = "陈鑫";
    }

    //有参构造:一旦定义了有参构造,无参就必须显示定义
    public Student(String name){
        this.name = name;	//左边的name是当前类的,右边的name是参数传进来的值
    }
}

demo1.java

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

        Student student = new Student();
        
        System.out.println("学生姓名为:"+student.name);

    }
}

快捷键 alt+insert

image-20220609090823669

image-20220609091051024

5.6、创建对象内存分析

Pet.java

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

    public void  shout(){
        System.out.println("bark");
    }
}

Application.java

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

        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;

        dog.shout();

        System.out.println(dog.name);
        System.out.println(dog.age);
    }
}

image-20220609094413877

image-20220609093817465

5.7、封装

  • 该露的露,该藏的藏,
    • 我们设计程序要追求“高内聚,低耦合”。
      高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
      低耦合:仅暴露少量的方法给外部使用
  • 封装(数据的隐藏)
    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏
  • 属性私有,get/set

image-20220609132000370

  • get、set可以使用快捷键alt+insert

    image-20220609132907195

    image-20220609133001683

演示

Application.java

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

        Student s1 = new Student();
        String name = s1.getName();

        s1.setName("陈鑫");
        System.out.println(s1.getName());

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

    }
}

Student.java

public class Student {

    //属性私有
    private String name;    //姓名
    private int age;        //年龄
    private char sex;       //性别

    //提供一些可以操作这个属性的方法!
    //提供一些public的get、set方法
    //get   获得这个数据
    public String getName(){
        return this.name;
    }
    //set   给这个数据设置值
    public void setName(String name){
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    }

    public char getSex() {
        return sex;
    }

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

image-20220609133952906

意义

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

5.8、继承

继承的定义

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
  • extends的意思是扩展,子类是父类的扩展
  • Java中类只有单继承,没有多继承!
  • 继承是类与类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
  • 子类和父类之间,从意义上讲应该具有“is a”的关系

image-20220609141756058

super

演示:super

demo1

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

        Student student = new Student();

        student.test1("陈鑫3");

        System.out.println("==================");

        student.test2();
    }
}

Student.java

public class Student extends Person{

    private String name = "陈鑫2";

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

    public void test2(){
       print();         //Student
       this.print();    //Student
       super.print();   //Person
    }

    public void test1(String name){
        System.out.println(name);       //陈鑫3
        System.out.println(this.name);  //陈鑫2
        System.out.println(super.name); //陈鑫1
    }
}

Person.java

public class Person {
    protected String name = "陈鑫1";
    public void print(){
        System.out.println("Person");
    }
}

image-20220609165253521

注意事项

super:

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

this:

  1. 代表的对象不同
    • this:本身调用这个对象
    • super:代表父类对象的引用
  2. 前提
    • this:没有前提也可以使用
    • super:只能在继承条件下才可以使用
  3. 构造方法
    • this():本类的构造
    • super():父类的构造

image-20220609170054438

方法重写

demo1.java

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

        //方法的调用只和左边,定义的数据类型有关
        /*
        即b是A new出来的对象,因此调用了A的方法
        因为静态方法是类的方法,而非静态是对象的方法
        有static时,b调用了B类的方法,因为b是用B类定义的
        没有static时,b调用的是对象的方法,而b是用A类new的
         */

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

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

A.java

public class A extends B{
    public  void test(){
        System.out.println("A=>test()");
    }
}

B.java

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

image-20220609180921503

注意事项

  1. 需要有继承关系,子类重写父类的方法!
  2. 方法名必须相同
  3. 参数列表必须相同
  4. 修饰符范围可以扩大,但不能缩小 public>protected>default>private
  5. 抛出的异常:范围,可以被缩小,但不能扩大 Exception --> ClassNotFoundException
  6. 快捷键:alt+insert;override
  7. 重写的意义:父类的功能,子类不一定需要,或者不一定能满足子类的需要

image-20220610091024744

5.9、多态

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式
  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
  • 多态存在的条件
    • 有继承关系
    • 子类重写父类方法
    • 父类引用指向子类对象
  • 多态是方法的多态,属性没有多态性

演示:多态

Application

public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //new Person();
        //new Student();

        //可以指向的引用类型就不确定了
        //父类的引用指向子类的类型
        //Student 能调用的方法都是自己的或者继承父类的!
        Student s1 = new Student();
        //Person 父类型,可以指向子类,但是不能调用子类独有的方法
        Person s2 = new Student();
        Object s3 = new Student();

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

Person.java

public class Person {

    public void run(){
        System.out.println("son");
    }

}

Student.java

public class Student extends Person{

    @Override
    public void run() {
        super.run();
    }
}

image-20220610154945409

注意事项

  1. 多态是方法的多态,属性没有多态
  2. 父类和子类,有联系 ,如果转换错误,会有类型转换异常 ClassCastException!
  3. 存在的条件:继承的关系,方法需要重写!如:如果没有重写,两个类中都有run,执行的时候就不知道执行哪一个
  4. 父类引用指向子类对象! Father f1 = new Son;
  5. 不能重写的
    • static 方法,属于类,它不属于实例
    • final 常量
    • private方法

5.10、instance和类型转换

定义:A instanceof B ,返回值为boolean类型,用来判断A是否是B的实例对象或者B子类的实例对象。如果是则返回true,否则返回false。

演示:instanceof

Application.java

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

        //Object    >   Person  >   Student
        //Object    >   Person  >   Teacher
        //Object    >   String
        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 Student();

        System.out.println(person instanceof Student);  //True
        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);  //编译报错!

    }
}

Person.java

javapublic class Person {

}

Student.java

public class Student extends Person{

}

Teacher.java

public class Teacher extends Person {

}

image-20220610162252593

演示:转换

Application.java

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

        //类型之间的转换:父-->子
        //高                     低   ,高转低需要强制转换
        Person person = new Student();

        //将person这个对象转换为Student类型,我们就可以使用Student类的方法了

        Student person1 = (Student) person;
        person1.go();

        //((Student)person).go();   一步完成转换

        //类型之间的转换:子-->父
        Student student = new Student();
        student.go();

        //子类转换为父类,可能丢失自己的本来的一些方法!
        Person person3 = student;


    }
}

Person.java

public class Person {



}

Student.java

public class Student extends Person{

    public void go(){
        System.out.println("go");
    }

}

image-20220610193327741

注意事项

  1. 父类引用指向子类的对象
  2. 把子类转换为父类,向上转型
  3. 把父类转换为子类,向下转型,强制转型
  4. 方便方法的调用,减少重复的代码

5.11、static关键字

定义:static是一个修饰符,用于修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能;被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

静态变量对于类,所有对象(实例)所共享,当直接使用类去调用得到,说明这个变量是静态的

非静态属性和静态属性

Student.java

public class Student {

    private static int age;     //静态变量
    private double score;       //非静态变量

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

        System.out.println(Student.age);
        System.out.println(student.age);
        System.out.println(student.score);
        //System.out.println(Student.score);


    }

}

image-20220610194501200

非静态方法和静态方法

Student.java

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

        new Student().run();    //非静态方法调用,需要实例化,new对象
        go();                   //静态方法调用,直接调用,不需要new

    }


    private static int age;     //静态变量
    private double score;       //非静态变量

    public void run(){           //非静态方法

        go();                   //这里也可以直接调用,static修饰的含义隶属于类,而不是对象,是一个公共的存储内存空间!
    }

    public static void go(){    //静态方法

    }

}

结论:static修饰的含义隶属于类,而不是对象,是一个公共的存储内存空间!

代码块

image-20220610200239917

匿名代码块和

public class demo1 {

        {   //匿名代码块作用:赋初始值
            System.out.println("匿名代码块");    //第二个执行
        }
        static {
            System.out.println("静态代码块");    //第一个执行,并且只能执行一次
        }

    public demo1() {
        System.out.println("构造方法");         //第三个执行
    }

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

image-20220610201315147

5.12、抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

image-20220610213023797

抽象

Action.java

//抽象类   单继承   (接口可以多继承)
public abstract class Action {

    //抽象方法,只有方法名字,没有方法的实现
    public abstract void doSth();
}

A.java

//抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非子类也是抽象类
public class A extends Action{

    @Override
    public void doSth() {

    }
}

注意事项

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

image-20220610213044656

5.13、接口的定义与实现

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有!
  • 接口:只有规范!无法自己写方法!专业的约束!约束和实现分离!
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是...则必须能...”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。
  • 接口的本质是契约,就像人世间的法律一样。
  • OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
  • 声明类的关键词是class,声明接口的关键词是interface

演示:接口

UserServiceImpl.java

package java;

//类 可以实现接口 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 timer() {

    }
}

UserService.java

package java;

//interface 定义的关键字,接口都需要有实现类
public interface UserService {
    //接口中的所有定义都是抽象的
    //public abstract可直接省去,因为接口中的定义默认都是抽象的
    //public abstract void run(String name);

    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

TimeService.java

package java;

public interface TimeService {
    void timer();
}

结论

理解

1.简单理解,抽象方法是指在创造这个方法的时候不确定这个具体的方法该怎么实现,于是交给想要实现此接口的人去重写

2.举个例子,猫和人都是动物,二者实现了动物的接口,动物有一个进食的抽象方法,具体实现交给人和猫去重写这个进食的方法

作用

1.约束

2.定义一些方法,让不同的人实现

3.方法都是public abstract

4.常量都是public static final

5.接口不能被实例化,因为接口中没有构造方法

6.implements可以实现多个接口

7.必须要重写接口中的方法

5.14、N种内部类

  • 内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,而A类想对于B类来说就是外部类了。
  • 分类:
    • 成员内部类
    • 静态内部类
    • 局部内部类
    • 匿名内部类

演示:成员内部类

Outer.java

package JavaSE;

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);
        }
    }
}

Application.java

package JavaSE;

public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();

        //通过这个外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getID();
    }

}

image-20220610224828590

6、异常

6.1、异常定义

  • 实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等。我们的程序在跑着,内存或硬盘就可能满了,等等。
  • 软件程序在运行的过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是Exception,意思是例外。这些情况,例外情况,或者叫异常,怎么让我们写的程序做出合理的处理。而不至于程序崩溃。
  • 异常指程序中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
  • 异常发生在程序运行期间,它影响了正常的程序执行流程。
  • 要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
    • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
    • 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
    • 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

image-20220611100641316

演示:无限循环,error

image-20220611094534217

image-20220611094549173

6.2、Error

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

6.3、Exception

  • 在Exception分支中有一个重要的子类RuntimeException (运行时异常)
    • ArraylndexOutOfBoundsException(数组下标越界)
    • ArithmeticException(算术异常)
    • NullPointerException(空指针异常)
    • MissingResourceException(丢失资源)
    • ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
  • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

6.4、异常处理机制

  • 抛出异常

  • 捕获异常

  • 异常处理五个关键字

    • try

    • catch

    • final

    • throw

    • throws

    • try、catch、final 快捷键 ctrl+alt+t

image-20220611105122018

抛出异常

package JavaSE;

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

      try{  //try监控区域
          System.out.println(a/b);
      }catch (ArithmeticException e){ //catch 捕获异常
          System.out.println("程序出现异常,变量b不能为0");
      }finally {    //finally处理善后工作,可要可不要
          System.out.println("finally");
      }
    }

}

image-20220611103532366

6.5自定义异常

  • 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
  • 在程序使用自定义异常类,大体可分为以下几个步骤:
    1. 创建自定义类
    2. 在方法中通过throw关键字抛出异常对象。
    3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
    4. 在出现异常方法的调用者中捕获并处理异常。
posted @ 2022-08-08 10:30  灵均c  阅读(64)  评论(0编辑  收藏  举报