IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 浅谈Java基础 -> 正文阅读

[Java知识库]浅谈Java基础

目录

一. java三大版本

二. 注释

三. 标识符和关键字

3.1. 标识符

3.2. 关键字

四. 数据类型

4.1. 数据类型

4.2. 数据类型扩展

4.2.1. 整数扩展

4.2.2. 浮点数扩展

4.2.3. 字符扩展

4.2.4. 转义字符

五. 类型转换

5.1. java数据类型优先级

5.2. 强制类型转换

5.3. 自动类型转换

六. 变量、常量和作用域

6.1. 变量

6.2. 变量作用域

6.3. 常量

6.4. 命名规范

七. 运算符

7.1. 算术运算符

7.2. 关系运算符

7.3. 逻辑运算符

7.4. 位运算符

7.5. 条件运算符

7.6. 扩展赋值运算符

7.7. 运算符优先级

八. 包机制

九. JavaDoc生成文档

十. Scanner用户交互

十一. 顺序结构

十二. 选择结构

12.1. if

12.2. switch...case...

十三. 循环结构

13.1. while循环

13.2. do...while循环

13.3. for循环

13.4. 增强型for循环

十四. break & continue & goto

14.1. break

14.2. continue

十五. 方法

15.1. 方法的定义

15.2. 值传递

15.3. 引用传递

15.4. 方法的调用

15.4.1 简单的调用

15.4.2. 静态方法与非静态方法的调用

15.5. 方法的重载

十六. 可变参数(不定项参数)

十七. 递归

十八. 数组

18.1. 数组的定义

18.2. 数组声明创建

18.3. 数组的初始化

18.4. 数组的四个基本特点

18.5. 多维数组

18.6. Arrays类

18.7. 冒泡排序

18.8. 稀疏数组

十九. 三种初始化和内存分析

二十. 面向对象编程

20.1. 面向对象简介

20.1.1 面向过程与面向对象

20.1.2. 什么是面向对象

二十一. 类与对象

21.1. 类与对象

21.2. 构造器

21.3. 封装

21.4. 继承

21.4.1. Object类

21.4.2. super 与 this

21.4.3. 方法重写

21.5. 多态

21.6. instanceof

21.7. 类型转换

二十二. static关键字详解

22.1. 静态变量和静态方法

22.2. 静态代码块

22.3. 静态导入包

二十三. 抽象类

二十四. 接口

二十五. 内部类

二十六. 异常

26.1. 异常的种类

26.2. 异常的体系

26.2.1 Error

26.2.2. Exception

26.3. 异常处理机制

26.4. 自定义异常


一. java三大版本

JavaSE 标准版(桌面程序,控制台开发...)

JavaME 嵌入式开发(手机,小家电...)

JavaEE 企业级开发(web端,服务器开发...)


二. 注释

  • 单行注释

// 单行注释
  • 多行注释

/*
*多行注释
*多行注释
*/
  • 文档注释

/**
*文档注释
*文档注释
*/


三. 标识符和关键字

3.1. 标识符

  • java所有组成部分都需要名字。类名、变量名和方法名都称为标识符

  • 所有标识符只能由 大小写字母、$号、_号 开始

  • 首字母之后可以由 大小写字母、$号、_号、数字 组成

  • 不能使用关键字作为标识符

  • 标识符大小写敏感


3.2. 关键字

abstractassertbooleanbreakbyte
catchcharclassconstcontinue
dodoubleelseenumextends
finallyfloatforgotoif
importinstanceofintinterfacelong
newpackageprivateprotectedpublic
strictfpshortstaticsuperswitch
thisthrowthrowstransienttry
voidvolatilewhilecasedefault

?


四. 数据类型

4.1. 数据类型

?

// byte
 ? ?byte num1 = 10;
// short
 ? ?short num2 = 20;
// int
 ? ?int num3 = 30;
// long
 ? ?long num4 = 30L;    // long类型后面要加L
// float
 ? ?float num5 = 10.0F; // float类型后面要加F
// double
 ? ?double num6 = 20.0;
// char
 ? ?char num7 = 'a';
// boolean
    boolean num8 = true;    // 大小为1位(bit,8位=1字节,即8b=1B)


4.2. 数据类型扩展

4.2.1. 整数扩展

/* 整数扩展
*  进制:二进制(以0b开头) ?  十进制 ?  八进制(以0开头) ?  十六进制(以0x开头)
* */
int num01 = 0b10;
int num02 = 10;
int num03 = 010;
int num04 = 0x10;
?
System.out.println(num01);  // 输出结果为2
System.out.println(num02);  // 输出结果为10
System.out.println(num03);  // 输出结果为8
System.out.println(num04);  // 输出结果为16


4.2.2. 浮点数扩展

// 浮点数扩展
float f = 0.1f;
double d = 1 / 10;
System.out.println(f==d);   // 输出结果为false(精度丢失)
// 尽量不适用浮点数进行比较(解决方法:使用Bigdecimal'数字工具类')


4.2.3. 字符扩展

// 字符扩展
char c1 = 'A';
char c2 = '好';
?
System.out.println(c1);     // 输出结果为A
System.out.println(c2);     // 输出结果为好
System.out.println((int)c1);// 输出结果为65
System.out.println((int)c2);// 输出结果为22909
?
/*所有字符本质还是数字
* 编码 Unicode表:65--A ? ? 97--a ?  22909--好
* */
?
// uFFFF Unicode表示
char c3 = '\u0061'; ? ?// 97的十六进制为61
System.out.println(c3);// 输出结果为a


4.2.4. 转义字符

// 转义字符
// 换行符:\n,制表符:\t...
?
System.out.println("hello\nworld");
/*输出结果为
* hello
* world*/
?
System.out.println("hello\tworld");
/*输出结果为
* hello ?  world
* */


五. 类型转换

注意:

  1. 运算中,不同类型的数值,先将转换成为同一类型,再进行运算

  2. 不能对boolean值进行转换

  3. 不能把对象类型转换成不相关的类型

  4. 把容量大的类型转换为容量小的类型时,须使用强制类型转换

  5. 转换过程中可能导致 内存溢出 或者 损失精度

5.1. java数据类型优先级

由低到高: byte,short,char—> int —> long—> float —> double


5.2. 强制类型转换

(类型)变量名 优先级由高转到低

int i=128;
byte b=(byte) i;
System.out.println(i); ?//输出结果为128
System.out.println(b); ?//输出结果为-128     //内存溢出
?
System.out.println((int)23.86); ?//输出结果为23
System.out.println((int)-43.63f); ?//输出结果为-43   //精度丢失


5.3. 自动类型转换

优先级由低转到高


六. 变量、常量和作用域

6.1. 变量

type varName [= value] [ , varName[=value] ;

// 数据类型 变量名 =值(可以有逗号隔开来声明多个变量)

注意:

  • java变量是程序中最基本的存储单元(包括:变量名、变量类型和作用域

  • 每个变量都必须声明类型(基本类型或引用类型)

  • 变量名必须是合法的标识符

  • 变量声明是一条完整的语句,必须以英文的分号结尾


6.2. 变量作用域

  • 类变量(静态变量)

      1. 从属于类

      2. 所有方法都能调用静态变量,非静态方法可以调用静态变量、实例变量和本方法的局部变量

        public class Variable {
         ? ?static double var = 1000;
         ? ?public static void main(String[] args) {
         ? ? ? ?System.out.println(var); ? ?//输出结果为1000.0
         ?  }
        }

  • 实例变量

      1. 从属于对象

      2. 如果不初始化,默认为 0 或 0.0 或 false 或 null

        public class Variable {
         ? ?int var01;
         ? ?String var02;
         ? ?public static void main(String[] args) {
         ? ? ? ?Variable variable = new Variable();
         ? ? ? ?System.out.println(variable.var02); //输出结果为null
         ? ? ? ?System.out.println(variable.var01); //输出结果为0
         ?  }
         ? ?public void var(){
         ? ? ? ?System.out.println(var01);  //输出结果为0
         ?  }
        }

  • 局部变量

      1. 必须声明并且初始化值

      2. 只能在本方法内使用

        public class Variable {
         ? ?public static void main(String[] args) {
         ? ? ? ?int var = 1;
         ? ? ? ?System.out.println(var); ? ?//输出结果为1
         ?  }
        }


6.3. 常量

final type varName [= value] [ , varName[=value] ;

// final 数据类型 常量名 =值(可以有逗号隔开来声明多个常量)

注意:

  • 常量初始化后不能再改变值

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

public class Constant {
 ? ?static final double A=1000;
 ? ?final static String B="Constant";   //final为修饰符,不区分前后顺序
 ? ?public static void main(String[] args) {
 ? ? ? ?final int C=100;
 ? ? ? ?System.out.println(A); ?//输出结果为1000.0
 ? ? ? ?System.out.println(B); ?//输出结果为Constant
 ? ? ? ?System.out.println(C); ?//输出结果为100
 ?  }
}


6.4. 命名规范

  • 所有变量、常量、方法、类名的起名要见名知意

  • 变量、方法名:首字母小写和驼峰原则(lastName、firstName())

  • 常量:大写字母和下划线(MAX_VALUE)

  • 类名:首字母大写和驼峰原则(public DataType{})


七. 运算符

基本运算符

(重点)

  • 算术运算符:+ - * / %(取模、取余) ++ --

  • 赋值运算符:=

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

  • 逻辑运算符:&&(与) ||(或) !(非)

(了解)

  • 位运算符:& | ^ ~ >> << >>>

  • 条件运算符:? :

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


7.1. 算术运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?int a=10;
 ? ? ? ?int b=20;
 ? ? ? ?System.out.println(a+b); ? ? ? ? ? ?//输出结果为30
 ? ? ? ?System.out.println(a-b); ? ? ? ? ? ?//输出结果为-10
 ? ? ? ?System.out.println(a*b); ? ? ? ? ? ?//输出结果为200
 ? ? ? ?System.out.println(a/(double)b); ? ?//输出结果为0.5
 ? ? ? ?
 ? ? ? ?System.out.println("===================================");
 ? ? ? ?
 ? ? ? ?System.out.println(b%a); ? ? ? ? ? ?//取余,取模,模运算,输出结果为0
 ? ? ? ?
 ? ? ? ?System.out.println("===================================");
 ? ? ? ?
 ? ? ? ?System.out.println(a); ?//a=10
 ? ? ? ?int c=a++;
 ? ? ? ?/*执行这行代码后,先给c赋值,再自增
 ? ? ? ? ? ?int c=a++;
 ? ? ? ? ? ?即
 ? ? ? ? ? ?int c=a;    //c=a=10
 ? ? ? ? ? ?a++;(a=a+1) //a=11
 ? ? ? ?*/
 ? ? ? ?System.out.println(c); ?//c=10
 ? ? ? ?System.out.println(a); ?//a=11
?
 ? ? ? ?int d=++a;
 ? ? ? ?/*执行这行代码前,先自增,再给d赋值
 ? ? ? ? ? ?int d=++a;
 ? ? ? ? ? ?等同于
 ? ? ? ? ? ?++a;(a=a+1) //a=12
 ? ? ? ? ? ?int d=a;    //d=a=12
 ? ? ? ?*/
 ? ? ? ?System.out.println(a); ?//a=12
 ? ? ? ?System.out.println(d); ?//d=12
 ? ? ? ?
 ? ? ? ?System.out.println("==================进阶1=================");
 ? ? ? ?
 ? ? ? ?System.out.println(a);  //a=12
 ? ? ? ?System.out.println(b);  //b=20
 ? ? ? ?System.out.println(a++ + ++b);  //输出结果为33
 ? ? ? ?/*
 ? ? ? ?b++;
 ? ? ? ?a + b;  <----输出的结果
 ? ? ? ?a++;
 ? ? ? ?*/
 ? ? ? ?
 ? ? ? ?System.out.println("==================扩展1--幂运算=================");
 ? ? ? ?
 ? ? ? ?// 很多运算,我们会使用一些工具类来操作
 ? ? ? ?// pow()方法的参数都是double类型的,所以变量只能为double
 ? ? ? ?double pow=Math.pow(2,3); ? // 2.0^3.0=2.0*2.0*2.0=8.0
 ? ? ? ?System.out.println(pow);    //输出结果为8.0
 ? ? ? ?
 ? ? ? ?System.out.println("==================扩展2--字符串连接符=================");
 ? ? ? ?
 ? ? ? ?
 ?  }
}


7.2. 关系运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?int a=10;
 ? ? ? ?int b=20;
 ? ? ? ?// 关系运算符返回结果为 正确 错误(布尔值)
 ? ? ? ?System.out.println(a>b); ? ?//输出结果为false
 ? ? ? ?System.out.println(a<b); ? ?//输出结果为true
 ? ? ? ?System.out.println(a==b); ? ?//输出结果为false
 ? ? ? ?System.out.println(a!=b); ? ?//输出结果为true
 ?  }
}


7.3. 逻辑运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?boolean e = true;
 ? ? ? ?boolean f = false;
 ? ? ? ?// 与(&&) 或(||) 非(!)
 ? ? ? ?System.out.println("e && f:"+(e && f)); //逻辑与运算:两个变量都为真才为true
 ? ? ? ?System.out.println("e || f:"+(e || f)); //逻辑或运算:两个变量有一个为真,则为true
 ? ? ? ?System.out.println("!(e && f):"+!(e && f)); //如果是真,则为假;反之,则为真
?
 ? ? ? ?System.out.println("==================扩展1=================");
?
 ? ? ? ?int g=10;
?
 ? ? ? ?System.out.println(g<4 && (g++>5)); //false
 ? ? ? ?System.out.println(g); ? ? ? ? ? ? ?//g=10
?
 ? ? ? ?System.out.println(g<4 && (++g>5)); //false
 ? ? ? ?System.out.println(g); ? ? ? ? ? ? ?//g=10
?
 ? ? ? ?// &&运算中,前一项为false时,则不再继续执行,所以g不变
?
 ? ? ? ?System.out.println(g>4 && (g++==10));//true(先比较,后自增)
 ? ? ? ?System.out.println(g); ? ? ? ? ? ? ? //g=11
?
 ? ? ? ?System.out.println(g>4 && (++g==11));//false(先自增,后比较)
 ? ? ? ?System.out.println(g); ? ? ? ? ? ? ? //g=12
 ?  }
}


7.4. 位运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?int h=42; ? //(42的二进制数为0010 1010)
 ? ? ? ?int i=30; ? //(30的二进制数为0001 1110)
 ? ? ? ?// &按位与运算,实则为二进制数每一位数字(0/1)的比较:同为0,则为0;同为1,则为1;不相同,则为0
 ? ? ? ?System.out.println(h&i); ? ?//结果为0000 1010[补码],而其原码的十进制数为10,则输出结果为10
 ? ? ? ?// |按位或运算,实则为二进制数每一位数字(0/1)的比较:同为0,则为0;同为1,则为1;不相同,则为1
 ? ? ? ?System.out.println(h|i); ? ?//结果为0011 1110[补码],而其原码的十进制数为62,则输出结果为62
 ? ? ? ?// ^异或运算,实则为二进制数每一位数字(0/1i)的比较:相同,则为0;不相同,则为1
 ? ? ? ?System.out.println(h^i); ? ?//结果为0011 0100[补码],而其原码的十进制数为52,则输出结果为52
 ? ? ? ?// ~取反运算,实则为二进制数每一位数字(0/1)的反转:1,则为0;0,则为1
 ? ? ? ?System.out.println(~h); ? ?//结果为1101 0101[补码],而其原码(1010 1011)的十进制数为-43,则输出结果为-43
?
 ? ? ? ?// <<左移运算,a<<b  --> a*2的b次方
 ? ? ? ?System.out.println(3<<3); ? //输出结果为24
 ? ? ? ?// >>右移运算,a>>b  --> a/2的b次方
 ? ? ? ?System.out.println(16>>3); ?//输出结果为2
 ?  }
}


7.5. 条件运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?// x ? y : z
 ? ? ? ?// 如果x==true,则结果为y,否则结果为z
 ? ? ? ?int score=70;
 ? ? ? ?String type = score<60 ? "不及格" : "及格";
 ? ? ? ?System.out.println(type);   //输出结果为 及格
 ?  }
}


7.6. 扩展赋值运算符

public class Operator {
 ? ?public static void main(String[] args) {
 ? ? ? ?int a=10;
 ? ? ? ?int b=20;
 ? ? ? ?a+=b;   //a=a+b;
 ? ? ? ?a-=b;   //a=a-b;
 ? ? ? ?a*=b;   //a=a*b;
 ? ? ? ?a/=b;   //a=a/b;
 ?  }
}


7.7. 运算符优先级

优先级运算符
1()、[]、{}
2!、~、++、–
3*、/、%
4+、-
5<<、>>、>>>
6<、<=、>、>=、instanceof
7==、!=
8&
9^
10|
11&&
12||
13?:
14=、+=、-=、*=、/=、&=、|=、^=、~=、?=、?=、>>>=


八. 包机制

注意:

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

    • 包语句的语法格式为:

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

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

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

    • 导入包语句的语法格式为:

      import package1[ . package2 ...] . (classname / *) ;


九. JavaDoc生成文档

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

  • 参数信息

    • @author 作者名

    • @version 版本名

    • @since 指明需要最早使用的jdk版本

    • @param 参数名

    • @return 返回值情况

    • @throws 异常抛出情况

方法一:命令行生成

进入命令行界面后 ----> 切换到需要生成文档的目录下输入

javadoc -encoding UTF-8 -charset UTF-8 Doc.java

// javadoc -encoding UTF-8 -charset UTF-8 需要生成API文档的Java文件

方法二:使用IDEA生成

找到Tools(工具) ----> Generate JavaDoc(生成JavaDoc)

?


十. Scanner用户交互

基本语法:

Scanner scanner = new Scanner(System.in);
...
scanner.close();    // 一定要关闭,否则会占用资源

  • 扩展1:通过Scanner类的next()与nextLine()方法可以获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据

    • import java.util.Scanner;
      ?
      public class UserInteraction {
       ? ?public static void main(String[] args) {
       ? ? ? ?//===================使用hasNext()与next()====================
       ? ? ? ?
       ? ? ? ?// 从键盘输入数据
       ? ? ? ?Scanner scanner = new Scanner(System.in); ? //输入hello world
       ? ? ? ?// 使用hasNext()判断用户有没有输入字符串
       ? ? ? ?if (scanner.hasNext()){
       ? ? ? ? ? ?// 使用next()方法接收
       ? ? ? ? ? ?String str=scanner.next(); ? ? ? ? ? ? ?// 程序会等待用户输入完毕
       ? ? ? ? ? ?System.out.println(str); ? ? ? ? ? ? ? ?//输出hello
       ? ? ?  }
       ? ? ? ?scanner.close();
       ?  }
      }
      • next()方法读取到空白符(空格、回车、tab...)就结束

    • import java.util.Scanner;
      ?
      public class UserInteraction {
       ? ?public static void main(String[] args) {
       ? ? ? ?//============使用hasNextList()与nextLine()====================
      ?
       ? ? ? ?// 从键盘输入数据
       ? ? ? ?Scanner scan = new Scanner(System.in); ? //输入hello world
       ? ? ? ?// 使用hasNextLine()判断用户有没有输入字符串
       ? ? ? ?if (scan.hasNextLine()){
       ? ? ? ? ? ?// 使用nextLine方法接收
       ? ? ? ? ? ?String str=scan.nextLine(); ? ? ? ? ? ? ?// 程序会等待用户输入完毕
       ? ? ? ? ? ?System.out.println(str); ? ? ? ? ? ? ? ?//输出hello world
       ? ? ?  }
       ? ? ? ?scan.close();
       ?  }
      }
      • nextLine()读取到回车结束

  • 扩展2:循环输入

    • import java.util.Scanner;
      ?
      public class UserInteraction {
       ? ?public static void main(String[] args) {
       ? ? ? ?// 输入多个数字,求其总和和平均数(每确认一个回车),通过输入非数字来结束,并输出结果
       ? ? ? ?Scanner scanner = new Scanner(System.in);
      ?
       ? ? ? ?double sum=0;// 求和
       ? ? ? ?int number=0;// 求个数
      ?
       ? ? ? ?// 通过循环判断是否输入数字,并在里面对每一次进行求和和统计
       ? ? ? ?while(scanner.hasNextDouble()){
       ? ? ? ? ? ?sum += scanner.nextDouble();
       ? ? ? ? ? ?number++;
       ? ? ?  }
      ?
       ? ? ? ?System.out.println("和为:" + sum + "\n平均数为:" + (sum/number));
       ? ? ? ?scanner.close();
       ?  }
      }


十一. 顺序结构

  • 最简单的算法结构

  • 一般按照顺序一句一句执行

案例:

public class SequentialStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?System.out.println("hello");
 ? ? ? ?System.out.println("world");
 ?  }
}


十二. 选择结构

12.1. if

  • if单选择结构

    • 语法:

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

  • if双选择结构

    • 语法:

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

  • if多选择结构

    • 语法:

      if(布尔表达式1){
       ? ?// 如果布尔表达式1为true,将执行的语句
      }else if(布尔表达式2){
       ? ?// 如果布尔表达式2为true,将执行的语句
      }else if(布尔表达式3){
       ? ?// 如果布尔表达式3为true,将执行的语句
      }else{
       ? ?// 如果以上布尔表达式都为false,将执行的语句
      }

      if语句只有一个else语句,并且else语句只能放在else if语句之后

      只要其中一个else if语句的布尔表达式为true,则直接结束,其余的else if语句和else语句都将跳过执行

案例:

int score=78;
if (score>80){
 ? ?System.out.println("优秀");
}else if(score>60){
 ? ?System.out.println("合格");
}else {
 ? ?System.out.println("不合格");
}
// 输出结果为 合格

  • 嵌套的if结构

    • 语法:

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


12.2. switch...case...

  • switch case多选择结构

    • 语法:

      switch(expression){
       ? ?case value1:
       ? ? ? ?// 语句
       ? ? ? ?break;// 可选
       ? ?case value2:
       ? ? ? ?// 语句
       ? ? ? ?break;// 可选
       ? ?default:// 可选
       ? ? ? ?// 语句
      }

      switch语句中变量可以是byte、short、int、char、String(JavaSE7开始支持)

      case后面只能跟常量

      default可以在switch语句的任何位置

      切记在case语句中缺少break,一般会出现case穿透现象

      switch语句遇见break才结束,否则程序默认执行到末尾结束

  • case穿透

案例:

public class SelectedStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?char score='B';
 ? ? ? ?switch (score){
 ? ? ? ? ? ?case 'A':
 ? ? ? ? ? ? ? ?System.out.println("优秀");
 ? ? ? ? ? ? ? ?break;
 ? ? ? ? ? ?case 'B':
 ? ? ? ? ? ? ? ?System.out.println("良好");
 ? ? ? ? ? ? ? ?//break;
 ? ? ? ? ? ?case 'C':
 ? ? ? ? ? ? ? ?System.out.println("还行");
 ? ? ? ? ? ? ? ?//break;
 ? ? ? ? ? ?default:
 ? ? ? ? ? ? ? ?System.out.println("合格");
 ? ? ?  }
 ?  }
}
/* 输出结果为
    良好
    还行
    合格
    
    因为case语句中缺少break,程序默认执行到末尾结束
*/


十三. 循环结构

13.1. while循环

while(布尔表达式){// 判断条件
 ? ?// 循环体
 ? ?// 迭代
}
  • 先判断,再执行

  • 只要布尔表达式为true,就一直执行下去

  • while(true){} 为死循环,尽量避免,除了少数情况服务器请求响应监听)

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 1+2+3+……+100=?
 ? ? ? ?int i=1;
 ? ? ? ?int sum=0;
 ? ? ? ?while (i<=100){
 ? ? ? ? ? ?sum+=i;
 ? ? ? ? ? ?i++;
 ? ? ?  }
 ? ? ? ?System.out.println(sum);
 ?  }
}
// 输出结果为 5050


13.2. do...while循环

do{
 ? ?// 循环体
 ? ?// 迭代
}while(布尔表达式);// 判断条件
  • 先执行,再判断(至少执行一次)

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 1+2+3+……+100=?
 ? ? ? ?int i=1;
 ? ? ? ?int sum=0;
 ? ? ? ?do {
 ? ? ? ? ? ?sum+=i;
 ? ? ? ? ? ?i++;
 ? ? ?  }while (i<=100);
 ? ? ? ?System.out.println(sum);
 ?  }
}
// 输出结果为 5050


13.3. for循环

for(初始化条件; 布尔表达式; 迭代){// 判断条件、迭代
 ? ?// 循环体
}
  • for循环语句时支持迭代的一种通用结构,是最有效、最灵活的循环结构

  • for( ; ; ){} 为死循环,尽量避免

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 1+2+3+……+100=?
 ? ? ? ?for (int i = 1; i <= 100; i++) {
 ? ? ? ? ? ?sum+=i;
 ? ? ?  }
 ? ? ? ?System.out.println(sum);
 ?  }
}
// 输出结果为 5050


13.4. 增强型for循环

for(声明语句 : 表达式){
 ? ?// 循环体
}
  • 主要用于数组或集合的增强型for循环

  • 声明语句:声明新的局部变量,该变量的类型必须和数组元素类型匹配,其作用域限定在循环语句块,其值与此时数组元素的值相等

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

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 遍历数组
 ? ? ? ?int[] numbers={10,20,30,40,50};
 ? ? ? ?for (int number : numbers){
 ? ? ? ? ? ?System.out.println(number);
 ? ? ?  }
 ?  }
}
/* 输出结果为
    10
    20
    30
    40
    50
*/


十四. break & continue & goto

14.1. break

  • 在任何循环语句主体部分,均可用break控制循环的流程

  • 用于强行退出循环,不执行循环中剩余的语句

  • 也能在switch语句中使用

  • 与return的区别:return一出,方法整个方法变结束了,return后面将不能再写代码

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?int i=0;
 ? ? ? ?while (i<100){
 ? ? ? ? ? ?i++;
 ? ? ? ? ? ?if (i==35){
 ? ? ? ? ? ? ? ?break;// 当i=35时,直接退出循环
 ? ? ? ? ?  }
 ? ? ? ? ? ?System.out.println(i);
 ? ? ?  }
 ?  }
}
/* 输出结果为
    1
    2
    3
    ...
    33
    34
*/


14.2. continue

  • 在循环语句中,用于终止某次循环,即跳出该次循环,再执行剩余的语句,接着进行下一次是否循环的判定

案例:

public class CyclicStructure {
 ? ?public static void main(String[] args) {
 ? ? ? ?int i=0;
 ? ? ? ?while (i<20){
 ? ? ? ? ? ?i++;
 ? ? ? ? ? ?if (i%5==0){// 当i为5的倍数时,跳过此次循环
 ? ? ? ? ? ? ? ?System.out.println();
 ? ? ? ? ? ? ? ?continue;
 ? ? ? ? ?  }
 ? ? ? ? ? ?System.out.print(i+" ");
 ? ? ?  }
 ?  }
}
/* 输出结果为
 ? ?1 2 3 4 
 ? ?6 7 8 9 
 ? ?11 12 13 14 
 ? ?16 17 18 19
*/


十五. 方法

什么是方法

  • 方法是语句的集合,它们在一起执行一个功能

  • 方法解决一类问题的步骤的有序组合

  • 方法包含在类或对象中

  • 方法在程序中被创建,在其他地方被引用

  • 设计原则:

    • 方法本意是功能块,就是实现功能的语句块的集合

    • 设计时,最好保持方法的原子性,就是一个方法只实现一个功能,这样有利于我们后期的扩展

  • 命名原则:

    • 首字母小写,驼峰原则


15.1. 方法的定义

方法包含一个方法头和一个方法体:

  • 方法头

    • 修饰符:可选择(public/private/protected/static/final/abstract...),定义该方法的方法类型

    • 返回值类型:

      • 有些方法有返回值,return valueType 中的 返回值valueType的数据类型就是本方法的返回值类型

      • 有些方法没有返回值,那本方法的返回值类型是void

      • 总之,返回值类型不能空着

    • 方法名:是方法的实际名称。

    • 参数类型:

      • 参数像是一个占位符,当方法被调用时,传递值给参数,这个值被称为实参或变量

        • 实参:调用方法时实际传给方法的数据

        • 形参:在方法被调用时用于接收外界输入的数据

      • 参数列表是指方法的参数类型、顺序和参数个数

      • 参数是可选的

      • 方法可以不包含任何参数

  • 方法体:方法体包含具体的语句,定义该方法的功能

修饰符 返回值类型 方法名(参数类型 参数名[,参数类型 参数名[,参数类型 参数名[...]]]){
    方法体;
    return 返回值;
}
?
或者
?
修饰符 void 方法名(参数类型 参数名[,参数类型 参数名[,参数类型 参数名[...]]]){
    方法体;
}


15.2. 值传递

值传递是在调用方法时,将实参复制一份内容副本传递到方法中,这样在函数中对参数进行修改,就不会影响到原来的实参

案例:

public class PassByValue {
 ? ?public static void main(String[] args) {
 ? ? ? ?int a=100;
 ? ? ? ?System.out.println(a);      // 输出结果为 100
?
 ? ? ? ?test(a);
?
 ? ? ? ?System.out.println(a);      // 输出结果为 100
 ?  }
 ? ?public static void test(int a){
 ? ? ? ?a=10;
 ?  }
}


15.3. 引用传递

引用传递是在调用方法时,将实参的地址直接传递到函数中。这样在函数中对参数进行的修改,就会影响到实参

public class PassByReference {
 ? ?public static void main(String[] args) {
 ? ? ? ?Person person = new Person();
 ? ? ? ?System.out.println(person.name);        // 输出结果为 null
?
 ? ? ? ?changeName(person);
 ? ? ? ?System.out.println(person.name);        // 输出结果为 hello
?
 ?  }
 ? ?public static void changeName(Person person){
 ? ? ? ?person.name="hello";
 ?  }
}
?
class Person { String name=null;}


15.4. 方法的调用

15.4.1 简单的调用

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

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

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

    • 例如:

      int a = add(3,4);
  • 如果方法返回值是void,方法调用一定是一条语句

    • 例如:

      System.out.println("hello world");


15.4.2. 静态方法与非静态方法的调用

// 不同类
package com.oop;
?
public class Method {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student.say(); ? ? ? ? ? ? ? ? ? ? ? ? ?// 静态方法:类名.方法名
 ? ? ? ?Student student = new Student(); ? ? ? ?// 非静态方法,调用方法一:对象名.方法名
 ? ? ? ?student.study();
 ? ? ? ?new Student().study(); ? ? ? ? ? ? ? ? ?// 非静态方法,调用方法二:对象名.方法名
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop;
?
public class Student{
 ? ?public static void say(){
 ? ? ? ?System.out.println("学生说");
 ?  }
 ? ?public void study(){
 ? ? ? ?System.out.println("学生再学习");
 ?  }
}

须知:静态方法只能调用静态方法和静态变量,而非静态方法不仅可以调用非静态方法和非静态变量,还可以调用静态方法和静态变量

原因: 类的静态方法和静态变量属于类,在类加载时就已经分配好内存,因此,可以通过类名直接访问,而非静态方法和非静态变量属于类的对象,只有在类的对象实例化时,才会分配内存,然后再通过实例化的对象去访问,所以,就会出现当一个类的静态方法去调用非静态方法或非静态变量时,会因为类的非静态方法或非静态变量可能不存在,从而导致出错

案例:

public class MethodDemo03 {
 ? ?// 都是静态的
 ? ?public static void a(){ b(); }
 ? ?public static void b(){ }
?
 ? ?// 都是非静态的
 ? ?public void c(){ d(); }
 ? ?public void d(){ }
?
 ? ?// 一个静态,被调用的方法为静态
 ? ?public void e(){ f(); }
 ? ?public static void f(){ }
?
 ? ?// 一个静态,调用方法的方法为静态
 ? ?public static void g(){ h(); }      // 此调用为错
 ? ?public void h(){ }
}


15.5. 方法的重载

  • 重载就是在一个类中,有相同的方法名称,但是形参不同的方法

  • 方法的重载原则:

    • 方法名称必须相同

    • 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等……)

    • 方法的返回值的类型可以相同也可以不相同。

    • 仅仅返回类型不同不足以成为方法的重载。

  • 实现理论:

    • 方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器会报错。

案例:

public class Method {
 ? ?public static void main(String[] args) {
 ? ? ? ?int a=10;
 ? ? ? ?double b=20;
 ? ? ? ?double c=30;
 ? ? ? ?System.out.println(add(a,b));
 ? ? ? ?System.out.println(add(b,c));
 ? ? ? ?System.out.println(add(a,b,c));
 ? ? ? ?System.out.println(add(b,a));
    }
 ? ?public static double add(int a,double b){
 ? ? ? ?return a+b;
 ?  }
 ? ?public static double add(double a,double b){            // 类型不同
 ? ? ? ?return a+b;
 ?  }
 ? ?public static double add(int a,double b,double c){      // 个数不同
 ? ? ? ?return a+b+c;
 ?  }
 ? ?public static double add(double a,int b){               // 参数排列顺序不同
 ? ? ? ?return a+b;
 ?  }
}
/* 输出结果为
 ? ?30.0
 ? ?50.0
 ? ?60.0
 ? ?30.0
*/


十六. 可变参数(不定项参数)

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

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

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

案例:

public class VariableParameters {
 ? ?public static void main(String[] args) {
 ? ? ? ?//调用可变参数的方法
 ? ? ? ?printMax();
 ? ? ? ?printMax(1,21,25,7,131,13,12);
 ? ? ? ?printMax(new double[]{21,12,32,4,5});
 ?  }
 ? ?public static void printMax(double... numbers){
 ? ? ? ?if (numbers.length==0){
 ? ? ? ? ? ?System.out.println("无数字");
 ? ? ? ? ? ?return;
 ? ? ?  }
 ? ? ? ?double temp=numbers[0];
?
 ? ? ? ?// 比较
 ? ? ? ?for (int i = 1; i < numbers.length; i++) {
 ? ? ? ? ? ?if (numbers[i]>temp){
 ? ? ? ? ? ? ? ?temp=numbers[i];
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?System.out.println("最大的数是:"+temp);
 ?  }
}
/* 输出结果为
 ? ?无数字
 ? ?最大的数是:131.0
 ? ?最大的数是:32.0
*/


十七. 递归

能不用就不用

  • 递归就是: A方法调用A方法,就是自己调用自己

  • 利用递归可以用简单的程序来解决些复杂的问题。

    • 它通常把个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次复计算,大大地减少了程序的代码量,递归的能力在于用有限的语句来定义对象的无限集合

  • 递归结构包括两个部分:

    • 递归头:什么时候不调用自身方法。如果没有尽头,将陷入死循环。

    • 递归体:什么时候需要调用自身方法。

案例:

public class Recursion {
 ? ?// 求一个数的阶层
 ? ?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);// 递归体
 ? ? ?  }
 ?  }
}
// 输出结果为 120


十八. 数组

18.1. 数组的定义

  • 数组是相同类型数据的有序集合

  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成

  • 其中,每一个数据称作一个数组的元素,每个数组元素可以通过一个下标来访问它们


18.2. 数组声明创建

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

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

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

    • dataType[] arrayRefVar = new dataType[arraySize];

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

  • 获取数组长度:

    • arrays. length

案例:

public class Array {
 ? ?public static void main(String[] args) {
 ? ? ? ?int[] num = new int[5];
 ? ? ? ?num[0]=10;
 ? ? ? ?num[1]=20;
 ? ? ? ?num[2]=30;
 ? ? ? ?num[3]=40;
 ? ? ? ?num[4]=50;
 ? ? ? ?System.out.println(num[3]);
 ?  }
}
// 输出结果为 40

18.3. 数组的初始化

  • 静态初始化

    • int[] array1 = {1,2,3};
  • 动态初始化

    • int[] array = new int[2];
      array[0]=1;
      array[1]=2;
  • 数组的默认初始化

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


18.4. 数组的四个基本特点

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

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

  • 数组中的元素可以是任何数据类型

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

  • 数组的合法边界是[0,array.length-1],越界会报错(ArrayIndexOutOfBoundsException:数组下标越界)


18.5. 多维数组

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

  • 二维数组

    • int a[ ][ ] = new int[2][5];
      // 这是一个有2个元素的数组,而每一个数组中又有5个元素
      // 可以看成一个两行五列的数组
  • 二维数组的使用?

    • num[1][0];


18.6. Arrays类

此类包含各种操作数组的方法(如:排序和搜索)

import java.util.Arrays;
?
public class Array {
 ? ?public static void main(String[] args) {
 ? ? ? ?int[] arrays01 = {11,22,380,4,50};
 ? ? ? ?int[] arrays02 = new int[5];
?
 ? ? ? ?// 打印数组元素
 ? ? ? ?System.out.println(Arrays.toString(arrays01)); ?        // 输出结果为[11, 22, 380, 4, 50]
?
 ? ? ? ?// 数组升序(从小到大)
 ? ? ? ?Arrays.sort(arrays01);                                  // 该方法无返回值,变化为永久的
 ? ? ? ?System.out.println(Arrays.toString(arrays01)); ?        // 输出结果为[4, 11, 22, 50, 380]
?
 ? ? ? ?// 填充赋值
 ? ? ? ?Arrays.fill(arrays02,10);
 ? ? ? ?System.out.println(Arrays.toString(arrays02)); ?        // 输出结果为[10, 10, 10, 10, 10]
 ? ? ? ?Arrays.fill(arrays02,1,3,20);
 ? ? ? ?System.out.println(Arrays.toString(arrays02)); ?        // 输出结果为[10, 20, 20, 10, 10]
?
 ? ? ? ?// 比较数组元素值是否相等
 ? ? ? ?System.out.println(Arrays.equals(arrays01,arrays02));   // 输出结果为false
?
 ? ? ? ?// 查找数组元素(二分法)
 ? ? ? ?System.out.println(Arrays.binarySearch(arrays01,3)); ? ?// -1(无该元素,返回-1)
 ? ? ? ?System.out.println(Arrays.binarySearch(arrays01,4)); ? ?// 0(有该元素,返回下标)
 ?  }
}


18.7. 冒泡排序

import java.util.Arrays;
?
//冒泡排序(升序、从小到大)
public class BubbleSort {
 ? ?public static void main(String[] args) {
 ? ? ? ?int[] array={23,12,545,88,1,8};
 ? ? ? ?System.out.println(Arrays.toString(bubbleSort(array)));// 输出结果为[1, 8, 12, 23, 88, 545]
 ?  }
?
 ? ?public static int[] bubbleSort(int[] array){
 ? ? ? ?int temp=0;
 ? ? ? ?// 外层循环代表循环次数
 ? ? ? ?for (int i = 0; i < array.length; i++) {
 ? ? ? ? ? ?// 内层循环代表依次比较
 ? ? ? ? ? ?for (int j = 0; j < array.length-i-1; j++) {
 ? ? ? ? ? ? ? ?if (array[j]>array[j+1]){
 ? ? ? ? ? ? ? ? ? ?temp=array[j];
 ? ? ? ? ? ? ? ? ? ?array[j]=array[j+1];
 ? ? ? ? ? ? ? ? ? ?array[j+1]=temp;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?return array;
 ?  }
 ? ?
}


18.8. 稀疏数组

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

  • 稀疏数组的处理方式是:

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

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

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

?以上图为例:

public class Array {
 ? ?// 1.创建一个二维数组,0:没有棋子,1:黑棋,2:白棋
 ? ?public static void main(String[] args) {
 ? ? ? ?// 展示原始数组
 ? ? ? ?int[][] arrays01 = new int[11][11];
 ? ? ? ?arrays01[1][2] = 1;
 ? ? ? ?arrays01[2][3] = 2;
 ? ? ? ?System.out.println("原始数组为:");
 ? ? ? ?arrayInfo(arrays01);
?
 ? ? ? ?// 转换为稀疏数组
 ? ? ? ?System.out.println("稀疏数组为:");
 ? ? ? ?int[][] arrays02 = sparseArray(arrays01);
 ? ? ? ?arrayInfo(arrays02);
?
 ? ? ? ?// 稀疏数组还原
 ? ? ? ?System.out.println("还原稀疏数组:");
 ? ? ? ?int[][] arrays03 = restoreSparseArray(arrays02);
 ? ? ? ?arrayInfo(arrays03);
 ?  }
?
 ? ?// 遍历二维数组
 ? ?public static void arrayInfo(int[][] arrays){
 ? ? ? ?for (int[] ints : arrays) {
 ? ? ? ? ? ?for (int anInt : ints) {
 ? ? ? ? ? ? ? ?System.out.print(anInt+"\t");
 ? ? ? ? ?  }
 ? ? ? ? ? ?System.out.println();
 ? ? ?  }
 ?  }
?
 ? ?// 转换为稀疏数组
 ? ?public static int[][] sparseArray(int[][] array){
 ? ? ? ?int count=0;// 获取有效值个数
 ? ? ? ?for (int i = 0; i < array.length; i++) {
 ? ? ? ? ? ?for (int j = 0; j < array[i].length; j++) {
 ? ? ? ? ? ? ? ?if(array[i][j]!=0){
 ? ? ? ? ? ? ? ? ? ?count++;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?// 创建稀疏数组
 ? ? ? ?int[][] arrays00 = new int[count+1][3];
 ? ? ? ?arrays00[0][0] = array.length;// 原数组的行数
 ? ? ? ?arrays00[0][1] = array[0].length;// 原数组的列数
 ? ? ? ?arrays00[0][2] = count;// 原数组不为0的个数
?
 ? ? ? ?// 判断是否在外循环接受前,已经获取到了所有的非0值,提前退出循环
 ? ? ? ?int temp=1;
 ? ? ? ?// 获取非0的值行数、列数和值
 ? ? ? ?for (int i = 0; i < array.length; i++) {
 ? ? ? ? ? ?for (int j = 0; j < array[i].length; j++) {
 ? ? ? ? ? ? ? ?if(array[i][j]!=0){
 ? ? ? ? ? ? ? ? ? ?arrays00[temp][0]=i;
 ? ? ? ? ? ? ? ? ? ?arrays00[temp][1]=j;
 ? ? ? ? ? ? ? ? ? ?arrays00[temp][2]=array[i][j];
 ? ? ? ? ? ? ? ? ? ?temp++;
 ? ? ? ? ? ? ?  }
 ? ? ? ? ?  }
 ? ? ? ? ? ?if(temp==arrays00[0].length){
 ? ? ? ? ? ? ? ?break;
 ? ? ? ? ?  }
 ? ? ?  }
 ? ? ? ?return arrays00;
 ?  }
?
 ? ?// 稀疏数组还原
 ? ?public static int[][] restoreSparseArray(int[][] array){
 ? ? ? ?//读取稀疏数组
 ? ? ? ?int[][] arrays00 = new int[array[0][0]][array[0][1]];
 ? ? ? ?// 还原值
 ? ? ? ?for (int i = 1; i <= array[0][2]; i++) {
 ? ? ? ? ? ?arrays00[array[i][0]][array[i][1]] = array[i][2];
 ? ? ?  }
 ? ? ? ?return arrays00;
 ?  }
}
/*输出结果为:
 ? ?原始数组为:
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   1   0   0   0   0   0   0   0   0   
 ? ?0   0   0   2   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?稀疏数组为:
 ? ?11  11  2   
 ? ?1   2   1   
 ? ?2   3   2   
 ? ?还原稀疏数组:
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   1   0   0   0   0   0   0   0   0   
 ? ?0   0   0   2   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0   
 ? ?0   0   0   0   0   0   0   0   0   0   0
*/


十九. 三种初始化和内存分析

?


二十. 面向对象编程

20.1. 面向对象简介

20.1.1 面向过程与面向对象

  • 面向过程思想

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

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

  • 面向对象思想

    • 物以类聚,分类的思维模式

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

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

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


20.1.2. 什么是面向对象

  • 面向对象编程(Object-Oriented Programming, 00P)

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

  • 抽象

  • 三大特性:

    • 封装

    • 继承

    • 多态

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

  • 从代码运行角度考虑是先有类后有对象。类是对象的模板。


二十一. 类与对象

21.1. 类与对象

  • 使用new关键字创建对象

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

  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。

  • 并且构造器有以下俩个特点:

    • 1.必须和类的名字相同

    • 2.必须没有返回类型,也不能写void

案例:

package com.oop;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student xiaoming = new Student();
 ? ? ? ?xiaoming.name = "小明";
 ? ? ? ?xiaoming.age=20;
 ? ? ? ?System.out.println(xiaoming.name);  // 小明
 ? ? ? ?System.out.println(xiaoming.age);   // 20
?
 ? ? ? ?Student xiaohong = new Student();
 ? ? ? ?xiaohong.name = "小红";
 ? ? ? ?xiaohong.age=18;
 ? ? ? ?System.out.println(xiaohong.name);  // 小红
 ? ? ? ?System.out.println(xiaohong.age);   // 18
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop;
?
public class Student {
 ? ?String name=null;
 ? ?int age=0;
 ? ?public void study(){
 ? ? ? ?System.out.println("在学习");
 ?  }
}


21.2. 构造器

  • 构造方法名必须与类名相同

  • 没有返回值

  • 作用

    • 使用new关键字,本质是在调用构造器

    • 用来初始化值的

    • 定义有参构造器后,若需要无参构造器,必须显示定义

package com.oop;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Person person01 = new Person();
 ? ? ? ?Person person02 = new Person("小明");
 ? ? ? ?Person person03 = new Person("小红",12);
 ? ? ? ?System.out.println(person01.name+" "+person01.age);     // null 0
 ? ? ? ?System.out.println(person02.name+" "+person02.age);     // 小明 0
 ? ? ? ?System.out.println(person03.name+" "+person03.age);     // 小红 12
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop;
?
public class Person {
 ? ?String name;
 ? ?int age;
?
 ? ?public Person() { ?                     //无参构造器
 ?  }
?
 ? ?public Person(String name) {            // 有参构造器
 ? ? ? ?this.name = name;
 ?  }
?
 ? ?public Person(String name, int age) {
 ? ? ? ?this.name = name;
 ? ? ? ?this.age = age;
 ?  }
}


21.3. 封装

  • 我们程序设计要追求”高内聚,低耦合“

    • 高内聚就是类的内部数据操作调节自己完成,不允许外部干涉

    • 低耦合:仅暴露少量的方法给外部类使用

  • 封装(隐藏数据) ●通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问

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

案例:

package com.oop.Demo01;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student student = new Student();
 ? ? ? ?student.setName("小明");
 ? ? ? ?student.setAge(1000);
 ? ? ? ?System.out.println(student.getName());// 小明
 ? ? ? ?System.out.println(student.getAge());// 18
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo01;
?
public class Student {
 ? ?private String name;
 ? ?private int age;
?
 ? ?public Student() { }
?
 ? ?public Student(String name, int age) {
 ? ? ? ?this.name = name;
 ? ? ? ?this.age = age;
 ?  }
?
 ? ?public void setName(String name) {
 ? ? ? ?this.name = name;
 ?  }
 ? ?
 ? ?public void setAge(int age) {
 ? ? ? ?if (age>120 || age<0){
 ? ? ? ? ? ?this.age=18;
 ? ? ?  }else{
 ? ? ? ? ? ?this.age = age;
 ? ? ?  }
 ?  }
 ? ?
 ? ?public String getName() {
 ? ? ? ?return name;
 ?  }
 ? ?
 ? ?public int getAge() {
 ? ? ? ?return age;
 ?  }
}

总结:

  • 提高程序的安全性,保护数据

  • 隐藏代码的实现细节

  • 统一接口

  • 系统可维护增加了


21.4. 继承

21.4.1. Object类

  • 在java中所有的类都直接或者间接继承Object类(超类)

  • 继承的本质是对某一批类的抽象,以此实现对实现世界更好的建模

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

  • Java类只有单继承,没有多继承

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

  • 继承关系的两个类,一个是子类,一个是父类,子类继承父类,使用关键字extends来表示

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


21.4.2. super 与 this

super注意点:

  • super调用父类的构造方法,必须在构造方法的第一个

  • super只能出现在子类的方法中

  • super和this不能同时调用构造方法

super与this的不同:

  • 两者代表的对象不同

    • this:本身调用者的这个对象

    • super:代表父类对应的引用

  • 两者前提不同

    • this:没有继承也能使用

    • super:只能在继承条件下使用

  • 两者构造方法不同

    • this:本类的构造方法

    • super:父类的构造方法

  • 案例一:

package com.oop.Demo02;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student student = new Student();
 ? ? ? ?student.info("小红");
 ?  }
}
/* 输出结果为:
 ? ?小红
 ? ?小明
 ? ?小明爸爸
*/
?
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Person {
 ? ?protected String name="小明爸爸";
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Student extends Person{
 ? ?private String name="小明";
?
 ? ?public void info(String name){
 ? ? ? ?System.out.println(name);
 ? ? ? ?System.out.println(this.name);
 ? ? ? ?System.out.println(super.name);
 ?  }
}
  • 案例二:

package com.oop.Demo02;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student student = new Student();
 ? ? ? ?student.info();
 ?  }
}
/*输出结果为:
 ? ?小明在学习
 ? ?小明在学习
 ? ?爸爸在工作
*/
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Person {
 ? ?protected String name="小明爸爸";
?
 ? ?public void print(){
 ? ? ? ?System.out.println("爸爸在工作");
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Student extends Person{
 ? ?private String name;
?
 ? ?@Override
 ? ?public void print() {
 ? ? ? ?System.out.println("小明在学习");
 ?  }
?
 ? ?public void info(){
 ? ? ? ?print();
 ? ? ? ?this.print();
 ? ? ? ?super.print();
 ?  }
?
}
  • 案例三:

package com.oop.Demo02;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student student = new Student("man","小明");
 ? ? ? ?student.info();//
?
 ?  }
}
/*输出结果为:
 ? ?man
 ? ?小明
*/
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Person {
 ? ?protected String sex;
?
 ? ?public Person() { }
?
 ? ?public Person(String sex) {
 ? ? ? ?this.sex = sex;
 ?  }
?
 ? ?public void info(){
 ? ? ? ?System.out.println(this.sex);
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo02;
?
public class Student extends Person{
 ? ?private String name;
?
 ? ?public Student() { }
?
 ? ?public Student(String sex, String name) {
 ? ? ? ?super(sex);
 ? ? ? ?this.name = name;
 ?  }
?
 ? ?@Override       
 ? ?public void info(){
 ? ? ? ?super.info();
 ? ? ? ?System.out.println(this.name);
 ?  }
}


21.4.3. 方法重写

  • 重写就是在子类中创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,但是方法的方法体中的实现不同于父类的功能

  • 方法的重写原则:

    • 两类得有继承关系,子类重写父类的方法

    • 参数列表必须完全相同

    • 如有返回值,返回值的类型要小于或者等于父类方法的返回值类型(Java1.5 版本之前返回值类型必须一样,之后的 Java 版本放宽了限制,返回值类型必须小于或者等于父类方法的返回值类型)

    • 访问权限不能比父类中被重写方法的访问权限低(public>protected>default>private)

    • 不能抛出比被重写方法声明更加宽泛的异常

  • 注意:

    • 重写的方法可以使用 @Override 注解来标识

    • 声明为 final 的方法不能被重写

    • 声明为 static 的方法不能被重写,但是能够再次声明

    • 声明为 private 的方法不能被重写

    • 构造方法不能被重写

    • 子类和父类在同一个包中时,子类可以重写父类的所有方法,除了声明为 private 和 final 的方法

    • 子类和父类不在同一个包中时,子类只能重写父类的声明为 public 和 protected 的非 final 方法

    • 如果不能继承一个方法,则不能重写这个方法

    • 重写的是方法,与属性无关

案例:

package com.oop.Demo03;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student student01 = new Student();
 ? ? ? ?student01.info();
?
 ? ? ? ?Person student02 = new Person();
 ? ? ? ?student02.info();
?
 ? ? ? ?Person student03 = new Student();
 ? ? ? ?student03.info();
 ?  }
}
/*输出结果为:
 ? ?Student.info
 ? ?Person.info
 ? ?Student.info
*/
-------------------------------------------------------------
 ? ?
package com.oop.Demo03;
?
public class Person {
 ? ?public void info(){
 ? ? ? ?System.out.println("Person.info");
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo03;
?
public class Student extends Person{
 ? ?@Override
 ? ?public void info() {
 ? ? ? ?System.out.println("Student.info");
 ?  }
}


21.5. 多态

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

  • 一个对象的实现类型是确定的,但可以指向 对象 的引用类型有很多

  • 多态的存在条件:

    • 有继承关系 (否则就会类型转换异常ClassCastException)

    • 子类重写父类方法

    • 父类引用指向子类对象:Fathero f=new son();

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

案例:

package com.oop.Demo04;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 一个对象的实际类型是确定的
 ? ? ? ?//new Student();
 ? ? ? ?//new Person();
 ? ? ? ?
 ? ? ? ?// 可以指向的引用类型就不确定:父类的引用指向子类
 ? ? ? ?
 ? ? ? ?// Student 能调用的方法都是自己的成就的或者继承父类
 ? ? ? ?Student student1=new Student();
 ? ? ? ?// Person 父类,可以指向子类; 使用方法:成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边
 ? ? ? ?// 可以简单理解为:编译时,对象能使用的方法都是父类决定的,而运行时,若被调用的方法已在子类的重写,则执行子类的方法;反之,则执行父类方法;而成员变量都是来自父类的
 ? ? ? ?Person student2=new Student();
 ? ? ? ?Object student3=new Student();
 ? ? ? ?
 ? ? ? ?student1.p();
 ? ? ? ?student2.p();
 ? ? ?  ((Student) student3).p();
 ?  }
}
/*输出结果为:
 ? ?s
 ? ?s
 ? ?s
*/
-------------------------------------------------------------
 ? ?
package com.oop.Demo04;
?
public class Person {
 ? ?public void p(){
 ? ? ? ?System.out.println("p");
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo04;
?
public class Student extends Person{
 ? ?@Override
 ? ?public void p() {
 ? ? ? ?System.out.println("s");
 ?  }
}


21.6. instanceof

  • 语法:对象 instanceof 类

  • 作用:判断该类是否是该对象的本类或父类或父类的父类...

package com.oop.Demo05;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Object stu1 = new Student();
?
 ? ? ? ?System.out.println(stu1 instanceof Student);//true
 ? ? ? ?System.out.println(stu1 instanceof Person);//true
 ? ? ? ?System.out.println(stu1 instanceof Object);//true
 ? ? ? ?System.out.println(stu1 instanceof Animal);//true
?
 ? ? ? ?System.out.println(stu1 instanceof Teacher);//false
 ? ? ? ?System.out.println(stu1 instanceof String);//false
 ? ? ? ?
 ? ? ? ?System.out.println("=================================================");
?
 ? ? ? ?Object stu2 = new Person();
?
 ? ? ? ?System.out.println(stu2 instanceof Student);//false
 ? ? ? ?System.out.println(stu2 instanceof Person);//true
 ? ? ? ?System.out.println(stu2 instanceof Object);//true
 ? ? ? ?System.out.println(stu1 instanceof Animal);//true
?
 ? ? ? ?System.out.println(stu2 instanceof Teacher);//false
 ? ? ? ?System.out.println(stu2 instanceof String);//false
 ? ? ? ? ? ? ? ?
 ? ? ? ?System.out.println("=================================================");
?
 ? ? ? ?Student stu3 = new Student();
?
 ? ? ? ?System.out.println(stu3 instanceof Student);//true
 ? ? ? ?System.out.println(stu3 instanceof Person);//true
 ? ? ? ?System.out.println(stu3 instanceof Object);//true
 ? ? ? ?System.out.println(stu1 instanceof Animal);//true
?
 ? ? ? ?System.out.println(stu3 instanceof Teacher);//编译时报错
 ? ? ? ?System.out.println(stu3 instanceof String);//编译时报错
 ? ? ? ? ? ? ? ? ? ? ? ?
 ? ? ? ?System.out.println("=================================================");
?
 ? ? ? ?Person stu4 = new Student();
?
 ? ? ? ?System.out.println(stu4 instanceof Student);//true
 ? ? ? ?System.out.println(stu4 instanceof Person);//true
 ? ? ? ?System.out.println(stu4 instanceof Object);//true
 ? ? ? ?System.out.println(stu4 instanceof Animal);//true
?
 ? ? ? ?System.out.println(stu4 instanceof Teacher);//false
 ? ? ? ?System.out.println(stu4 instanceof String);//编译时报错
 ?  }
}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo05;
?
public class Animal{}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo05;
?
public class Person extends Animal{}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo05;
?
public class Teacher extends Person{}
?
-------------------------------------------------------------
 ? ?
package com.oop.Demo05;
?
public class Student extends Person{}


21.7. 类型转换

  • 由低转高

    • 语法: 父类类型 变量名 = 子类对象;

  • 由高转低(强制转换)

    • 语法:(子类类型)变量名

案例:

package com.oop.Demo06;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Person teacher = new Teacher();
 ? ? ? ?teacher.p();            //Person
 ? ? ?  ((Teacher)teacher).t(); //Teacher
 ?  }
}
-------------------------------------------------------------
?
package com.oop.Demo06;
?
public class Person{
 ? ?public void p(){
 ? ? ? ?System.out.println("Person");
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop.Demo06;
?
public class Teacher extends Person{
 ? ?public void t(){
 ? ? ? ?System.out.println("Teacher");
 ?  }
}


二十二. static关键字详解

22.1. 静态变量和静态方法

package com.oop.Demo07;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?Student s = new Student();
 ? ? ? ?System.out.println(s.age); ? ? ? ? ?//10
 ? ? ? ?s.studentName(); ? ? ? ? ? ? ? ? ? ?//小红
 ? ? ? ?System.out.println(Student.name); ? //小明
 ? ? ? ?Student.studentAge(); ? ? ? ? ? ? ? //18
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop.Demo06;
?
public class Student {
 ? ?int age=10;                         //非静态变量
 ? ?static String name="小明";         ? //静态变量
?
 ? ?public void studentName(){          //非静态方法
 ? ? ? ?System.out.println("小红");
 ? ? ? ?//studentName();                //非静态方法可以调用静态方法,静态不能调用非静态方法
 ?  }
?
 ? ?public static void studentAge(){    //静态方法
 ? ? ? ?System.out.println(18);
 ?  }
}


22.2. 静态代码块

  • 类一加载就直接执行,永久只执行一次

package com.oop.Demo07;
?
public class Application {
 ? ?
 ? ?// 匿名代码块:类一加载就执行,可用于赋初始值
 ?  {
 ? ? ? ?System.out.println("匿名代码块");
 ?  }
?
 ? ?// 静态代码块:类一加载就执行,顺序比匿名代码块早,但永久只执行一次
 ? ?static {
 ? ? ? ?System.out.println("静态代码块");
 ?  }
?
 ? ?// 当代码块都执行完后,再执行构造方法
 ? ?public Application(){
 ? ? ? ?System.out.println("构造方法");
 ?  }
 ? ?public static void main(String[] args) {
 ? ? ? ?Application application = new Application();
 ? ? ? ?System.out.println("===============================");
 ? ? ? ?Application application1 = new Application();
 ?  }
}
/* 输出结果为:
 ? ?静态代码块
 ? ?匿名代码块
 ? ?构造方法
 ? ?===============================
 ? ?匿名代码块
 ? ?构造方法
*/


22.3. 静态导入包

package com.oop.Demo07;
?
// 静态导入包
import static java.lang.Math.random;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?System.out.println(random());
 ?  }
}


二十三. 抽象类

  • 抽象类不能实例化对象,只能靠子类继承

  • 抽象类可以写非抽象方法(可以具体实现)

  • 抽象方法必须在抽象类中(抽象方法是一种规范,只能在子类中实现)

  • 抽象类有构造器

  • 抽象类的子类必须重写抽象方法,除非该子类也是抽象类,则可以选择性重写

package com.oop.Demo08;
?
public abstract class Person {      // 抽象类
 ? ?public abstract void a();           // 抽象方法
 ? ?
 ? ?public Application() {              // 构造方法
 ?  }
 ? ?
 ? ?public void b() {                   // 非抽象方法
 ? ? ? ?System.out.println("hello");
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop.Demo08;
?
public class Student extends Person{
 ? ?@Override
 ? ?public void a() {
 ? ? ? ?System.out.println("world");
 ?  }
}


二十四. 接口

  • 接口与非抽象类和抽象类的区别:

    • 非抽象类:只有具体的实现

    • 抽象类:既有具体的实现,又有规范(抽象方法)

    • 接口:只有规范

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

  • 实现了接口的类,必须重写接口的方法

  • 接口不能实例化对象,接口没有构造方法

  • 一个类可以实现多个接口

package com.oop.Demo09;
?
public class UserServiceImpl ?implements UserNameService,UserAgeService{
 ? ?@Override
 ? ?public void addUserName(String name) {
?
 ?  }
?
?
 ? ?@Override
 ? ?public void addUserAge(String name) {
?
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop.Demo09;
?
// 定义接口关键字是interface,
public interface UserNameService {
 ? ?// 接口中所有定义都是抽象的,public abstract
 ? ?void addUserName(String name);
}
?
-------------------------------------------------------------
?
package com.oop.Demo09;
?
public interface UserAgeService {
 ? ?void addUserAge(String name);
}


二十五. 内部类

  • 内部类就是在一个类内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类

    • 成员内部类

    • 静态内部类

    • 局部内部类

    • 匿名内部类

package com.oop.Demo10;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 外部类
 ? ? ? ?Outer outer = new Outer();
 ? ? ? ?outer.out();
 ? ? ? ?// 成员内部类
 ? ? ? ?Outer.Inner01 inner1 = outer.new Inner01(); ? ? ?// 通过外部类来实例化内部类
 ? ? ? ?inner1.in();
 ? ? ? ?inner1.getOutInfo();
 ? ? ? ?// 静态内部类
 ? ? ? ?Outer.Inner02 inner2 = new Outer.Inner02();
 ? ? ? ?inner2.in();
 ? ? ? ?inner2.getOuterInfo();
 ? ? ? ?// 局部内部类
 ? ? ? ?outer.outMethod();
 ? ? ? ?// 匿名内部类
 ? ? ? ?// 如果一个内部类在整个操作中只使用一次的话,就可以定义为匿名内部类。匿名内部类也就是没有名字的内部类,这是java为了方便我们编写程序而设计的一个机制,因为有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适。
 ? ? ? ?new ATest().info();
 ?  }
}
?
class ATest{
 ? ?public void info(){
 ? ? ? ?System.out.println("匿名内部类");
 ?  }
}
?
-------------------------------------------------------------
?
package com.oop.Demo09;
?
public class Outer {
?
 ? ?private int id=10;
 ? ?private static String name="小明";
?
 ? ?public void out(){
 ? ? ? ?System.out.println("这是外部类的方法");
 ?  }
?
 ? ?// 成员内部类
 ? ?public class Inner01{
 ? ? ? ?public void in(){
 ? ? ? ? ? ?System.out.println("这是成员内部类的方法");
 ? ? ?  }
?
 ? ? ? ?public void getOutInfo(){
 ? ? ? ? ? ?System.out.println(name); ? ? ? ? ? ? ? // 可以获取外部类的私有属性
 ? ? ? ? ? ?System.out.println(id);
 ? ? ?  }
 ?  }
?
 ? ?// 静态内部类
 ? ?public static class Inner02{
 ? ? ? ?public void in(){
 ? ? ? ? ? ?System.out.println("这是静态内部类的方法");
 ? ? ?  }
?
 ? ? ? ?public void getOuterInfo(){
 ? ? ? ? ? ?System.out.println(name); ? ? ? ? ? ? ?// 静态类获取的外部类的私有属性必须是静态的
 ? ? ?  }
 ?  }
?
 ? ?// 局部内部类
 ? ?public void outMethod(){
 ? ? ? ?class Inner03{
 ? ? ? ? ? ?public void in(){
 ? ? ? ? ? ? ? ?System.out.println("这是局部内部类的方法");
 ? ? ? ? ?  }
?
 ? ? ? ? ? ?public void getOuterInfo(){
 ? ? ? ? ? ? ? ?System.out.println(name); ? ? ? ? ? ? ? // 可以获取外部类的私有属性
 ? ? ? ? ? ? ? ?System.out.println(id);
 ? ? ? ? ?  }
 ? ? ?  }
?
 ? ? ? ?// 局部内部类需要在该方法的最后实例化
 ? ? ? ?Inner03 inner3 = new Inner03();
 ? ? ? ?inner3.in();
 ? ? ? ?inner3.getOuterInfo();
 ?  }
}
?


二十六. 异常

26.1. 异常的种类

  • 要解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:

    • 检查性异常:

      最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

    • 运行时异常:

      运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

    • 错误:

      错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。


26.2. 异常的体系

  • Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。

  • 在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception

26.2.1 Error

  • Error类对象由Java虚拟机生成并抛出的,大多数的错误与代码编写者所执行的操作无关。

  • Java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。当这些异常发生时,Java虚拟机(JVM) 一般会选择线程终止;

  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError) 、链接错误(LinkageError) 。这些错误是不可查的,因为它们在应用程序的控制和处理能力外,而且绝大多数是程序运行时不允许出现的状况。


26.2.2. Exception

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

    • ArraylndexOutOfBoundsException (数组下标越界)

    • NullPointerException (空指针异常)

    • ArithmeticException (算术异常)

    • MissingResourceException (舌失资源)

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

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

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


26.3. 异常处理机制

  • 抛出异常

  • 捕获异常

  • 异常处理五个关键字:try, catch, finally, throw, throws

  • 如果要不获取多个异常,要从小到大捕获

案例1----捕获异常:

package com.exception.Demo01;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?try{
 ? ? ? ? ? ?System.out.println(20/0);
 ? ? ?  }catch (ArithmeticException e1){ ? ? ? ? ? ? ? ? ? ? // 捕获异常
 ? ? ? ? ? ?System.out.println("ArithmeticException");
 ? ? ?  }catch (Exception e2){
 ? ? ? ? ? ?System.out.println("Exception");
 ? ? ?  }finally { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// finally可以不用写,用于善后工作,如在IO中在finally代码块内写关闭资源的代码
 ? ? ? ? ? ?System.out.println("finally用于善后工作");
 ? ? ?  }
?
 ? ? ? ?System.out.println();
 ?  }
}
?
/*输出结果为:
 ? ?ArithmeticException
 ? ?finally用于善后工作
*/

案例2----自动抛出异常:

package com.exception.Demo02;
?
public class Application {
 ? ?public static void main(String[] args) {
 ? ? ? ?int num=10;
 ? ? ? ?if (num==10) {
 ? ? ? ? ? ?throw new NumberFormatException();              // 自动抛出异常 throw 异常对象;
 ? ? ?  } else {
 ? ? ? ? ? ?System.out.println(num);
 ? ? ?  }
 ?  }
}


26.4. 自定义异常

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

  • 用户自定义异常类,只需继承Exception类即可

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

      1. 创建自定义异常类,并继承Exception类

      2. 在方法中通过throw关键字抛出异常对象

      3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作

      4. 在出现异常方法的调用者中捕获并处理异常

案例:

package com.exception.Demo03;
?
public class Application {
?
 ? ?static void test(int num) throws MyException{
 ? ? ? ?if (num<10){
 ? ? ? ? ? ?throw new MyException(num);
 ? ? ?  }else {
 ? ? ? ? ? ?System.out.println("num="+num);
 ? ? ?  }
 ?  }
?
 ? ?public static void main(String[] args) throws MyException{
 ? ? ? ?try{
 ? ? ? ? ? ?test(8);
 ? ? ?  }catch (MyException e){
 ? ? ? ? ? ?System.out.println("捕获异常为:"+e);
 ? ? ?  }
 ?  }
}
?
-------------------------------------------------------------
?
package com.exception.Demo03;
// 自定义异常
public class MyException extends Exception{
 ? ?private int num;
?
 ? ?// 传递大于10的数字
 ? ?public MyException(int num) {
 ? ? ? ?this.num = num;
 ?  }
?
 ? ?// toString 打印异常信息
 ? ?@Override
 ? ?public String toString() {
 ? ? ? ?return "MyException{" + "num=" + num + '}';
 ?  }
}
?
/*输出结果为:
    捕获异常为:MyException{num=8}
*/

总结:

  • 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理

  • 在多重catch块后面,可以加一个catch (Exception)来处理可能会被遗漏的异常

  • 对于不确定的代码,也可以加上try-catch,处理潜在的异常

  • 尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出

  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定

  • 尽量添加finally语句块去释放占用的资源

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 08:57:09  更:2021-08-29 08:58:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:59:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码