狂神说Java笔记-Java基础
Java基础
狂神说JAVA视频课笔记,狂神说JAVA
1. 注释
- 单行注释://
- 多行注释:/* 注释 */
- JavaDoc文档注释注释:/** */
- /**开头
- */结尾
- 每行开头一个*
- 有关键字,自定义的关键字在帮助文档中是不显示的(如@Description,加了@反而不能在帮助文档显示,不如不加@)
- JavaDoc标记
- JavaDoc注释规范
public class Hello {
public static void main(String[] args) {
//单行注释
System.out.println("Hello,World!");
/*
多行注释
多行注释
*/
//JavaDoc:文档注释 /** */
/**
* Hello, world!
* @author Dong
*/
}
}
2. 数据类型
- 强数据类型:要求变量的使用要严格符合规定,所有变量必须先定义后使用。
- 定义后不经过类型转换无法转换成其他数据类型。
- 安全性高,速度慢。
- 弱类型语言
Java数据类型:
- 基本类型(primitive type)
- 引用类型(reference type)
基本类型
Long类型要在数字后加L:long num=10L;
,l
和L
都可以标识长整型,但l
容易看成数字1,所以用L
比较规范。
float类型要在数字后加F:float num=10.1F;
字符串String不是关键字,是类
引用数据类型
- 类
- 接口
- 数组
数据类型拓展及面试题
1. 整数拓展:
-
二进制:
0b
开头 -
八进制:
0
开头 -
十六进制:
0x
开头public class Demo1 { public static void main(String[] args) { int i=10; int i_2=0b10;//二进制 0b 开头 int i_8=010;//八进制 0 开头 int i_16=0x10;//十六进制 0x 开头 System.out.println(i); System.out.println(i_2); System.out.println(i_8); System.out.println(i_16); } }
2. 浮点数拓展
银行业务中,钱怎么表示?
避免使用浮点数进行比较
浮点数是不精确的(有限的;离散的;有舍入误差的;大约;接近但不等于)
例子:
public class DataTypeDemo {
public static void main(String[] args)
//浮点数
float f=0.1f; //0.1
double d=1.0/10; //0.1
System.out.println(f==d);
//期望输出true,但实际输出false
float d1=1234424234523422342343421f;//这里数小了会输出false
float d2=d1+1;
System.out.println(d1==d2);
//期望输出false,但实际输出true
}
}
所以在遇到银行业务这类需要比较浮点数的情况,使用BigDecimal类(数学工具类)
3. 转义字符
- \t:制表符tab
- \n:换行
3. 类型转换
在进行运算前,需要先将不同类型的数据转换成统一的数据类型
- 从高到低需要进行强制类型转换
- 强制类型转换:(类型名)变量名
- 从低到高进行自动类型转换
注意⚠️
-
不能对布尔值进行转换
-
不能把对象类型转换为不相干的类型
-
在把高容量转换为低容量时,需要使用强制类型转换
-
转换时可能出现内存溢出问题和精度问题
-
字符型转换成整型时,转换成的是该字符的ascii码
数字字符转换成整型时,要用该字符-‘0’:int number=‘4’-‘0’
public class TypeConversion {
public static void main(String[] args) {
//强制转换 高-》低
int i=128;
byte b=(byte)i;
//内存溢出,byte存储范围[-128,127]
System.out.println(i);
System.out.println(b);//输出-128
System.out.println("======================================");
//======================================
//自动转换 低-》高
int ii=128;
double bb=ii;
System.out.println(ii);
System.out.println(bb);//输出128.0
System.out.println("======================================");
}
}
溢出问题
在进行数据的计算时,得到的数可能会出现溢出的问题。这时要先把进行计算的其中一个数转换为高容量的数据类型,然后在进行计算。
- 不能先计算再进行数据类型转换,因为计算完后的数的默认数据类型是原数据的数据类型,这样在进行数据类型转换前就已经溢出了
public class Overflow {
public static void main(String[] args) {
//操作比较大的数的时候,注意溢出问题
int money = 10_0000_0000;//JDK7新特性,数字之间可以用下划线分割
int year = 20;
int total = money * year;//输出一个负数,计算的时候溢出的
long totalLong = money * year;//先用原始的int类型计算完再转为long类型,所以转换之前已经出错
//正确做法是在计算前先把一个数的数据类型转化为long类,再计算乘法
long totalLongRight = money * ((long) year);
System.out.println("用int储存的:" + total);//输出-1474836480
System.out.println("用long储存但先计算的:" + totalLong);//输出-1474836480
System.out.println("用long储存且先类型转换的:" + totalLongRight);//输出期望结果20000000000
}
}
4. 变量、常量和作用域
变量
作用域
- 类变量(修饰符static):static+数据类型+变量名
- 可以不初始化
- 可以在方法中直接调用
- 实例变量
- 从属于对象,需要声明不需要初始化
- 在方法中调用前,需要先将类实例化(新建一个对象)
- 局部变量
- 必须声明和初始化值,只在方法内有效
public class Scope {
//属性:变量
//类变量 static,可以不初始化
static double salary = 2500;
//实例变量:从属于对象,需要声明不需要初始化
// 实例变量不初始化的话,默认值为0 0.0
//布尔值默认是false
//除了基本类型,其余默认值都是null
String name;
int age;
//main方法
public static void main(String[] args) {
//局部变量:必须声明和初始化值,只在方法内有效
int i = 10;
Scope s = new Scope();
System.out.println(s.age);//age没有初始化,但可以输出,输出为0
System.out.println(salary);//类变量可以直接输出,输出2500
}
//其他方法
}
5. 运算符
算术运算符
对于long
、int
、short
和byte
:
- 当进行运算的变量有long类型,则运算结果的数据类型为
long
- 否则全部为
int
,即使是short
和byte
类型的变量,运算结果也是in
b=++a
和b=a++
:
++a
:先自增,再给b赋值a++
:先给b赋值,再自增
幂运算:
- Math.pow(底数,指数);
逻辑运算符
短路运算:
当根据逻辑运算符前面的表达式就可以得出逻辑运算的结果时,逻辑运算符后面的表达式不再执行。
int c=5;
boolean d=(c<4) && (c++<4);
System.out.println(d);//输出false
System.out.println(d);//输出5
位运算
位运算效率高
- &:与
- |:或
- ^:异或
- ~:非,取反
- <<:左移,相当于乘2
- >>:右移,相当于除以2
面试题:2*8=16,怎样运算最快
答:用位运算最快
0000 0001 1
0000 0010 2
0000 0100 4
0000 1000 8
0001 0000 16
所以把2
左移3,就可以得到16
System.out.printlin(2<<3);//输出16
扩展赋值运算符
-
a+=b:a=a+b
-
a-=b:a=a-b
-
字符串连接符 +
- 当+一边出现字符串类型时,运算返回的是字符串类型。运算符优先级不变,还是从左到右
System.out.printlin(""+1+2);//12 System.out.printlin(1+2+"");//3,先进行加法运算,再与字符串连接 注意:System.out.printlin(""+(1+2));// 3
三元运算符
- x ? y : z(掌握,常见)
- 如果x==true,则返回y,否则返回z
5. 包机制
包的本质就是文件夹
一般利用公司域名倒置作为包名
防止命名空间重复
-
在src里新建一个包
-
取消compact middle packages
- 可以在域名下加属于他的功能
包的导入
为了使用其他包的成员,需要在java程序中使用import导入改包(idea可以设置自动导入包),导入的其他包的方法名不能和程序中的方法名一样。
.*为通配符,可以导入包下所有的类
import java.util.*
6. JavaDoc
将注释信息生成自己的帮助文档/API文档
使用命令行生成帮助文档
-
使用文档注释 /** */
-
打开代码所在位置(mac:右键.java文件,点击Reveal in Finder)
-
打开命令行,cd到代码所在文件夹,运行:
javadoc -encoding UTF-8 -charset UTF-8 程序名.java
-encoding utf-8 -charset utf-8 为了能够显示中文
-
生成帮助文档
使用IDEA生成帮助文档
- Tools --> Generate JavaDoc
- 参数:-encoding UTF-8 -charset UTF-8 -windowtitle “文档HTML页面标签的标题” -link http://docs.Oracle.com/javase/8/docs/api
Java流程控制
Scanner对象
-
之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner 是Java5的新特征,我们可以通过Scanner类来获取用户的输入。
-
基本语法:
Scanner S = new Scanner( System. in);
-
通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。
-
next()和hasNext()
public class Demo02_Scanner { 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(); } }
-
nextLine()和hasNextLine()
public class Demo02_Scanner { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("使用nextLine方式接收: "); //判断是否还有输入 if (scanner.hasNextLine()) { String str = scanner.nextLine(); System.out.println("输出的内容为: " + str); } scanner.close(); } }
-
next():
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next() 不能得到带有空格的字符串。
-
nextLine():
- 以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符。
- 可以获得空白。
- 使用语法
public class Demo02_Scanner {
public static void main(String[] args) {
Scanner scanner = new Scanner(System. in);
System.out.println("请输入数据: ");
String str = scanner.nextLine( );
System.out .println( "输出的内容为: "+str);
scanner.close();
}
}
- 其他hasNextInt()和hasNextFloat()
public class Demo03_Scanner {
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();
}
}
- 输入多个数字,并求其总和与平均数
import java.util.Scanner;
public class Demo04_Scanner {
public static void main(String[] args) {
//我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果:
Scanner scanner = new Scanner(System.in);
double sum = 0;
int m = 0;
//通过循环判断是否还有输入,并在里面对每-次进行求和和统计
while (scanner.hasNextDouble()){
double x = scanner.nextDouble();
m=m+1; //m++
sum=sum+x;
System.out.println("你输入了第"+m+"个数据,然后当前结果sum=" +sum) ;
}
System.out.println(m + "个数的和为" + sum);
System.out.println(m +"个数的平均值是" + (sum / m));
scanner.close();
}
}
switch多选择结构
-
多选择结构还有一个实现方式就是switch case语句。
-
switch case语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
-
switch 语句中的变量类型可以是:
-
byte、short, int 或者char.
-
从JavaSE7开始,switch支持字符串String类型了
- 字符的本质是数字
- java文件
public class Demo05_Switch { public static void main(String[] args) { String name = "狂神"; switch (name){ case "秦疆": System.out.println("秦疆"); break; case "狂神": System.out.println("狂神"); break; default : System.out.println("弄啥嘞! "); } } }
-
class文件(hashCode())
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.base; public class Demo05_Switch { public Demo05_Switch() { } public static void main(String[] args) { String name = "狂神"; byte var3 = -1; switch(name.hashCode()) { case 941788: if (name.equals("狂神")) { var3 = 1; } break; case 997472: if (name.equals("秦疆")) { var3 = 0; } } switch(var3) { case 0: System.out.println("秦疆"); break; case 1: System.out.println("狂神"); break; default: System.out.println("弄啥嘞! "); } } }
-
同时case标签必须为字符串常量或字面量。
-
增强for循环
-
这里我们先只是见一面,做个了解,之后数组我们重点使用
-
Java5引入了一种主要用于数组或集合的增强型for循环。
-
Java增强for循环语法格式如下:
for(声明语句:表达式) { //代码句子 }
- 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循 环语句块,其值与此时数组元素的值相等。
- 表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
public class Demo06_Foreach {
public static void main(String[] args) {
int[] numbers = {10,20,30,40,50}; //定义了一个数组
//遍历数组的元素
for (int x: numbers){
System.out.println(x);
}
}
}
break continue
- break在任何循环语句的主体部分,均可用break控制循环的流程。*break用于强行退出循环,不执行循环中剩余的语句*。(break语句也在switch语句中使用)
- continue语句用在循环语句体中,*用于终止某次循环过程*,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
- 关于goto关键字 goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的- 个保留字,但并未在语言中得到正式使用; Java没有goto。然而,在break和continue这两个关键字的身上,我们仍然能看出一些goto的影子——带标签的break和continue.
- "标签" 是指后面跟一个冒号的标识符,例如: label:
- 对Java来说唯一 用到标签的地方是在循环语句之前。 而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
public class Demo07_Label {
public static void main(String[] args) {
//打101- 150之问所有的质数
int count = 0;
//不建议使用!
outer:for (int i = 101;i < 150;i++){
for (int j = 2; j < i/2;j++){
if (i %j== 0){
continue outer;
}
}
System.out.print(i+" ");
}
}
}
方法
何谓方法?
-
System.out.println(), 那么它是什么呢?
-
Java方法是语句的集合,它们在一起执行一个功能。
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建, 在其他地方被引用
-
设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成1个功能,这样利于我们后期的扩展。
-
回顾:方法的命名规则?
方法的定义
-
Java的方法类似于其它语言的函数,是-段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:
-
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
-
修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
-
返回值类型:方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
-
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
-
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 形式参数:在方法被调用时用于接收外界输入的数据。
- 实参:调用方法时实际传给方法的数据。
-
方法体:方法体包含具体的语句,定义该方法的功能。
修饰符 返回值 类型 方法名(参数类型参数名){ 方法体 return返回值; }
-
方法调用
- 调用方法:对象名.方法名(实参列表)
- Java支持两种调用方法的方式,根据方法是否返回值来选择。
- 当方法返回一个值的时候,方法调用通常被当做一个值。例如: int larger = max(30,40);
- 如果方法返回值是void,方法调用一定是一条语句。 System. out. println( "Hello, kuangshen!");
- 课后拓展了解:值传递(Java)和引用传递
方法的重载
-
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
-
方法的重载的规则:
- 方法名称必须相同。
- 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
- 方法的返回类型可以相同也可以不相同。
- 仅仅返回类型不同不足以成为方法的重载。
-
实现理论:
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
命令行传参
有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
public class CommandLine {
public static void main(String args[]){
for(int i=0; i<args.length; i++){
System. out. println("args["+ i + "]:"+ args[i]);
}
}
}
可变参数
- JDK 1.5开始,Java支持传递同类型的可变参数(不定项)给一个方法。
- 在方法声明中,在指定参数类型后加一个省略号(..)。
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public class Demo08 {
public static void main(String args[]) {
//调用可变参数的方法
printMax(15,22.0,36,25.3);
printMax(new double[]{1, 2, 3});//本质为数组
}
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);
}
}
递归(能不用就不用)
- 递归就是: A方法调用A方法!就是自己调用自己
- 利用递归可以用简单的程序来解决一些复杂的问题。 它通常把一个大型复杂的问题层层转化为-个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
- 递归结构包括两个部分:
- 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。
- 递归体:什么时候需要调用自身方法。
内存分析
三种初始化
-
静态初始化
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;
-
数组的默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
数组的四个基本特点
- 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
- 数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
小结:
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合
- 数组也是对象。数组元素相当于对象的成员变量
- 数组长度的确定的,不可变的。如果越界,则报: ArrayIndexOutofBounds
数组使用
-
For-Each循环
public class Demo09_Array { public static void main(String[] args) { int[] arrays = {1,2,3,4,5}; //JDK1.5,没有下标 for (int array : arrays) { System.out.println(array); } } }
-
数组作方法入参
public class Demo09_Array { public static void main(String[] args) { int[] arrays = {1,2,3,4,5}; printArray(arrays); } //打印数组元素 public static void printArray(int[] arrays){ for (int i = 0; i < arrays.length; i++) { System.out.print(arrays[i]+" "); } } }
-
数组作返回值
public class Demo09_Array { public static void main(String[] args) { int[] arrays = {1,2,3,4,5}; int[] reverse = reverse( arrays); printArray(reverse); } //反转数组 public static int[] reverse(int[] arrays){ int[] result = new int [arrays.length]; //反转的操作 for (int i = 0,j=result.length-1; i < arrays.length; i++,j--) { result[j] = arrays[i]; } return result; } //打印数组元素 public static void printArray(int[] arrays){ for (int i = 0; i < arrays.length; i++) { System.out.print(arrays[i]+" "); } } }
多维数组
-
多维数组可以看成是数组的数组,比如维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
-
二维数组
int a[][] = new int[2][5];
- 解析:二维数组a可以看成一个两行三列的数组。
-
思考:多维数组的使用?
Arrays类
-
数组的工具类java.util.Arrays
-
由于数组对象本身并没有什么方法可以供我们调用,但API中提供了-一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。
查看JDK帮助文档
-
Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而"不用"使用对象来调用(注意:是"不用"而不是"不能")
-
具有以下常用功能:
-
给数组赋值:通过fill方法。
-
对数组排序:通过sort方法,按升序。
Arrays.sort(a); System.out.println(Arrays.toString(a));
-
比较数组:通过equals方法比较数组中元素值是否相等。
-
查找数组元素: 通过binarySearch方法能对排序好的数组进行二分查找法操作。
-
package com.base;
import java.util.Arrays;
public class Demo10_Arrays {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 9090, 31231, 543, 21, 3, 23};
System.out.println(a); // 数组对象的hashcode [I@4554617c
//打印数组元素Arrays.tostring
System.out.println(Arrays.toString(a));
printArray(a);
}
//自己编写打印数组的方法
public static void printArray(int[] a) {
for (int i = 0; i < a.length; i++) {
if (i == 0) {
System.out.print("[");
}
if (i == a.length - 1) {
System.out.print(a[i] + "]");
} else {
System.out.print(a[i] + ", ");
}
}
}
}
冒泡排序
-
冒泡排序无疑是最为出名的排序算法之一, 总共有八大排序!
-
冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人尽皆知。
-
我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为0(n2)。
import java.util.Arrays; //1. 比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置 //2. 每一次比较,都会产生出一个最大,或者最小的数字; //3. 下一轮则可以少一次排序! //4. 依次循环,直到结束! public class Demo11 { public static void main(String[] args) { int[] a = {1, 4, 5, 6, 72, 2, 2, 2, 25, 6, 7}; int[] sort = sort(a); //调用完我们自己写的排序方法以后,返回一个排序后的数组 System.out.println(Arrays.toString(sort)); } public static int[] sort(int[] array) { //临时变量 int temp = 0; //外层循环,判断我们这个要走多少次; for (int i = 0; i < array.length - 1; i++) { Boolean flag = false; //内层循环,比价判断两个数,如果第一个数,比第二个数大,则交换位置 for (int j = 0; j < array.length - 1 - i; j++) { if (array[j + 1] > array[j]) { temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; flag = true; } } if (flag == false){ break; } } return array; } }
稀疏数组介绍
- 当一个数组中大部分元素为0,或者为同一-值的数组时,可以使用稀疏数组来保存该数组。
- 稀疏数组的处理方式是:
- 记录数组一共有几行几列,有多少个不同值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
public class Demo12_Sparse {
public static void main(String[] args) {
//创建一个元素的二维数组 11*11 0:没有棋子 1: 黑棋 2: 白棋
int chessArry1[][] = new int[11][11];
chessArry1[1][2] = 1;
chessArry1[2][3] = 2;
for (int [] row : chessArry1) {
for ( int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
int[][] paraseArr = transformSparseArr(chessArry1);
transformArry(paraseArr);
}
//二维数组 转 稀疏数组
public static int[][] transformSparseArr( int[][] arry) {
int sum =0; // 有效值的个数
int rowSize = 0;
//1、计算出有效的个数
for (int[] row :arry) {
for ( int data :row) {
rowSize = row.length;
if (data != 0) {
sum++;
}
}
}
//创建稀疏数组 并给稀疏数组赋值
int [][] sparseArr= new int[sum+1][3];
sparseArr [0][0] = arry.length;
sparseArr [0][1] = rowSize;
sparseArr [0][2] = sum;
//count 计数器 计算放入的有效个数 即第几个非零数据
int count = 0;
for (int i = 0; i < arry.length; i++) {
for (int j = 0; j < rowSize ; j++) {
if (arry[i][j] != 0) {
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = arry[i][j];
}
}
}
// 输出稀疏数组形式
System.out.println("===========稀疏数组============");
for (int i = 0; i < sparseArr.length; i++) {
// %d 占位符 \t 制表符 \n 换行
System.out.printf("%d\t%d\t%d\t\n", sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]);
}
System.out.println();
return sparseArr;
}
// 稀疏数组 转化为 二维数组
public static int[][] transformArry(int[][] parseArr) {
int row = parseArr[0][0]; //得到行
int col = parseArr[0][1]; //得到列
//数组恢复 并赋值
int[][] arry = new int[row][col];
for (int i = 1 ; i < parseArr.length; i++) {
arry[parseArr[i][0]][parseArr[i][1]] = parseArr[i][2];
}
// 输出
System.out.println("============二维数组恢复==============");
for (int [] rows: arry) {
for (int data : rows) {
System.out.printf("%d\t", data);
}
System.out.println();
}
return arry;
}
}
面向对象编程
面向过程&面向对象
面向过程思想
- 步骤清晰简单,第-步做什么,第二C步做什么....
- 面对过程适合处理一些较为简单的问题
面向对象思想
- 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
- 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
什么是面向对象
- 面向对象编程(Object-Oriented Programming, 00P)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。“
- 抽象.
- 三大特性:
- 封装
- 继承
- 多态
- 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
- 从代码运行角度考虑是先有类后有对象。类是对象的模板。
回顾方法及加深
方法的定义
- 修饰符 返回类型
/*
修饰符返回值类型方法名 (...){
//方法体
return返回值;
}
*/
public String sayHe11o(){
return "he1lo , world";
}
pub1ic int max (int a,int b){
return a>b ? a : b; //三元运算符!
}
-
break 和return的区别:
break跳出循环,return结束当前方法
-
方法名 参数列表
-
异常抛出
public void readFile(String file) throws IOException{}
方法的调用
静态方法
1、可以通过类直接调用,在类加载时加载,不能调用非静态方法
public class Demo01Static {
public static void main(String[] args) {
Student.say();
}
}
public class Student {
public static void say(){
System.out.println("学生说话了");
}
}
非静态方法
通过实例化对象调用
public class Demo01Static {
public static void main(String[] args) {
Student student = new Student();
student.say();
}
}
public class Student {
public void say(){
System.out.println("学生说话了");
}
}
形参和实参
值传递和引用传递
引用传递
public class Demo02 {
//引用传递:对象,本质还是值传递
//对象,内存!|
public static void main(String[] args) {
Perosn perosn = new Perosn();
System.out.println(perosn.name); //nuLL
Demo02.change(perosn);
System.out.println(perosn.name); //秦疆
}
public static void change(Perosn perosn){
//perosn是一个对象:指向的---> Perosn perosn = new Perosn();
// 这是一个具体的人, 可以改变属性!
perosn.name = "秦疆";
}
}
//定义了- -个Perosn类,有一个属性: name
class Perosn{
String name; //null
}
值传递
public class Demo03 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);//a=1
a(a);
System.out.println(a);//a=1
}
public static void a(int a){
a=10;
}
}
this关键字
类与对象的关系.
- 类是一种抽象的数据类型,它是对某一类事物整体描述定义,但是并不能代表某一个具体的事物. 动物、植物、手机、电.... . Person类、Pet类、 Car类等, 这些类都是用来描述/定义某-类具体的事物应该具备的特点和行为
- 对象是抽象概念的具体实例
- 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例。
- 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念
创建与初始化对象
-
使用new关键字创建对象
-
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
//类中只有属性和方法 public class Student { //属性 String name; int age; //方法 public void say(){ System.out.println("学生说话了"); } }
public class Applications { public static void main(String[] args) { //类:抽象的,实例化 // 类实例化后会返回一个自己的对象! // student对象就是一个Student 类的具体实例! Student xiaoming = new Student( ); xiaoming.name = "小明"; xiaoming.age = 3; System.out.println(xiaoming.name); System.out.println(xiaoming.age); } }
-
类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下俩个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
-
构造器必须要掌握
public class Person { //一个类即使什么都不写,它也会存在个方法 //显示的定义构造器 String name ; int age; //alt+ insert //1.使inew关键字, 本质是在调用构造器 //2.用例初始化值 public Person(){ } //有参构造:一旦定义 了有参构造。无参就必须显示定义 public Person(String name){ this.name = name ; } public Person(String name, int age) { this. name = name; this.age = age; } }
-
构造器:
- 和类名相同
- 没有返回值
-
作用:
- new本质在调用构造方法
- 初始化对象的值
-
注意点:
定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造
初始化对象时的内存情况:
-
-
封装
-
该露的露,该藏的藏
我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
-
封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
-
记住这句话就够了:属性私有,get/set
//类中只有属性和方法
public class Student {
//类 private: 私有
//属性私有
private String name; //名字
private int id; //学号
private char sex; //性别
private int age;
//提供一些可以操作这个属性的方法!
//提供——public的get. set方法
//get获得这个数据
public String getName(){
return this.name;
}
//set给这个数据设置值
public void setName(String name){
this.name = name;
}
//alt + insert
public int getAge() {
return age;
}
public void setAge(int age) {
if(age <0 || age > 120){
this.age = 3;
}else {
this.age = age;
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
- 好处
- 提高程序的安全性,保护数据.
- 隐藏代码的实现细节
- 统一接口
- 系统可维护增加了
继承
-
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
-
extands的意思是“扩展”。子类是父类的扩展。
-
JAVA中类只有单继承,没有多继承!
-
被final修饰的类不能被继承。
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
- 继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
- 子类和父类之间,从意义上讲应该具有"is a"的关系.
-
object类
java中的所有类都直接或间接继承Object类
-
super
- super注意点:
- super调用 父类的构造方法,必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中!
- super和 this 不能同时调用构造方法!
- Vs this:
- 代表的对象不同: this 本身调用者这个对象 super:代表父类对象的应用
- 前提 this:没有继承也可以使用 super:只能在继承条件才可以使用
- 构造方法 this() ; 本类的构造 super():父类的构造!
// 子类维承了父类,就会拥有父类的全部方法! public class Student extends Person{ public Student() { //隐藏代码:调用了父类的无参构造 super(); // 调用父类的构造器,必领要在子类构造器的第一一行 System.out.println("Student无参执行了"); } public Student(String name) { this .name = name ; } private String name = "qinjiang" ; public void print(){ System.out.println("Student"); } public void test1(){ print();//Student this.print();//Student super.print();//Person } }
public class Person { //一个类即使什么都不写,它也会存在个方法 //显示的定义构造器 protected String name ="kuangshen"; int age; //alt+ insert //1.使inew关键字, 本质是在调用构造器 //2.用例初始化值 public Person(){ System.out.println("Person"); } //有参构造:一旦定义 了有参构造。无参就必须显示定义 public Person(String name){ this.name = name ; } public void print(){ System.out.println("Person"); } }
- super注意点:
-
方法重写
父类静态方法
public class Demo04_A extends Demo04_B{
public static void test(){
System.out.println("A==>test()");
}
}
//重写都是方法的重写,和属性无关
public class Demo04_B {
public static void test(){
System.out.println("B==>test()");
}
}
public class Applications {
public static void main(String[] args) {
//Demo04
//方法的调用只和左边,定义的数据类型有关
Demo04_A a = new Demo04_A();
a.test();//A==>test()
//父类引用指向引用
Demo04_B b = new Demo04_A();
b.test();//B==>test()
}
}
父类非静态方法
public class Applications {
public static void main(String[] args) {
//Demo04
/*
静态方法和非静态方法区别很大
静态方法:方法的调用只和左边,定义的数据类型有关
非静态方法:重写,父类方法只能是public
*/
Demo04_A a = new Demo04_A();
a.test();//A==>test()
//父类引用指向引用
Demo04_B b = new Demo04_A();//子类重写了父类的方法
b.test();//A==>test()
}
}
//重写都是方法的重写,和属性无关
public class Demo04_B {
public void test(){
System.out.println("B==>test()");
}
}
public class Demo04_A extends Demo04_B{
@Override
public void test() {
System.out.println("A==>test()");
}
}
- 重写:需要有继承关系,子类重写父类的方法!
- 方法名必须相同
- 参数列表列表必须相同
- 修饰符:范围可以扩大但不能缩小:public>Protected >Default>private
- 抛出的异常:范围,可以被缩小,但不能扩大: ClassNotFoundException --> Exception(大)
- 重写,子类的方法和父类必要一 致;方法体不同!
- 为什么需要重写:
- 父类的功能,子类不一定需要, 或者不一定满足!
- Alt +Insert ;---->override;
多态
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 注意:多态是方法的多态,属性没有多态性。
public class Person {
public void run(){
System.out.println("Person==>run()");
}
}
public class Student extends Person{
@Override
public void run() {
System.out.println("Student==>run()");
}
public void stop(){
System.out.println("Student==>stop()");
}
}
public class Applications {
public static void main(String[] args) {
// 一个对象的实际类型是确定的:new Student();new Person();
//可以指向的引用类型就不确定了:父类的引用指向子类
//Student 能调用的方法都是自己的或者继承父类的!
Student s1 = new Student();
//Person 父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大!
s2.run(); //子类重写了父类的方法。执行子类的方法 Student==>run()
s1.run();//Student==>run()
s1.stop();//Student==>stop()
Person p1 = new Person();
p1.run();//Person==>run()
}
}
- 多态注意事项:
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 类型转换异常! ClassCastException!
- 存在条件: 继承关系,方法需要重写,父类引用指向于类对象! Father f1 = new Son();
- 不能进行多态的方法:
- static 方法,属于类,它不属于实例
- final常量;
- private 方法;|
- instanceof:(类型转换)引用类型, 判断一个对象是什么类型~
public class Applications {
public static void main(String[] args) {
Object object = new Student();
//System. out . println(X instanceof Y);//能不能编译通过! X,Y之间要存在父子关系
//System. out . println(X instanceof Y);// X是Y之的子类,true
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); //不能通过编译
}
}
- 转换
- 父类转子类
public class Application {
public static void main(String[] args) {
//类型之间的转化:父子
//高 低
Person obj = new Student();
//student将这个对象转换为Student类型,我们就可以使lstudent类型的方法了!
((Student) obj).go();
}
}
-
子类转父类
public class Application { public static void main(String[] args) { //类型之间的转化:父 子 //子类转换为父类,可能丢失自己的本来的一些方法! Student student = new Student(); student.go(); Person person = student; } }
- 总结
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型;
- 把父类转换为子类,向下转型;强制转换
- 方便方法的调用,减少重复的代码!简介
- 封装、继承、多态! 抽象类,接口
static
public class Student {
//2:赋初值~
{
System.out.println("匿名代码块");
}
//1 :只执行一次~
static {
System.out.println("静态代码块");
}
//3
public Student() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Student student = new Student();
System.out.println("==========");
Student student2 = new Student( );
}
}
//静态导入包~
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class demo01 {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方;如;果修饰类,那么该类就是抽象类。
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
- 抽象类,不能使用new关键字来创建对象, 它是用来让子类继承的。
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法, 否则该子类也要声明为抽象类。
//约束有人帮我们实现~
public abstract class Action {
//abstract, 抽象方法,只有方法名字,没有方法的实现!
public abstract void run();
public void go(){
System.out.println("Action==>go()");
}
//1. 不能new这个抽象类,只能靠子类去实现它;约束!
//2. 抽象类中可以写普通的方法~
//3. 抽象方法必须在抽象类中~
//抽象的抽象:约束~
//思考题? new,存在构造器么? 存在
//存在的意义抽象出来~ 提高开发效率
}
public class A extends Action{
//必须实现父类的抽象方法,除非其本身也是抽象类
@Override
public void run() {
System.out.println("A==>run()");
}
}
接口
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)都有!
-
接口:只有规范! 自己无法写方法~专业的约束!约束和实现分离:面对接口编程
-
接口就是规范,定义的是一组规则,体现了现实世界中“如果你...则必须能.的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
oo的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++. java、 c#等) ,就是因为设计模式所研究的,实际上就是如何合理的去抽象。
public interface UserService {
//interface定义的关键字,按口都需 要有实现类
//常量~ pubsic static final,一般不在接口中定义常量
int AGE = 99;
//按口中的所有定义的方法其实都是抽象的public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface TimeService {
void timer();
}
//抽象类: extends~
//类可以实现接口implements 按口
//实现了按口的类,就需要重写接口中的方法~
//多继承~利用接口实现多继承
public class UserServiceImpl implements UserService, TimeService {
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
-
总结:
-
方法public abstract
-
常量public static final
-
接口不能被实例化~,接口中没有构造方法~
-
implements 可以实现多个接口
-
必须要重写接口中的方法~
内部类
-
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
-
成员内部类
public class Outer { private int age = 10; public void out(){ System.out.println("这是外部类的方法"); } public class Inner{ public void in(){ System.out.println("这是内部类的方法"); } public void getAge(){ System.out.println(age); } } }
public class Applications { public static void main(String[] args) { //demo09 Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.getAge(); inner.in(); outer.out(); } }
-
静态内部类
-
局部内部类
//局部内部类 public void method(){ class Inner1{ public void in1(){ } } }
-
匿名内部类
什么是异常
-
实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等。我们的程序再跑着,内存或硬盘可能满了。等等。
-
软件程序在运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是:Exception,意思是例外。这些,例外情况,或者叫异常,怎么让我们写的程序做出合理的处理。而不至于程序崩溃。
-
异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
-
异常发生在程序运行期间,它影响了正常的程序执行流程。
-
要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
-
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
-
运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
-
错误ERROR:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
-
异常体系结构
- Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有是常的超类。
- 在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。
- Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
- Java虚拟机运行错误(Virtual MachineError) ,当JVM不再有继续执行操作所需的内存资源 时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM) 一般会选择线程终 止;
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError) 、链接错误 (LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且 绝大多数是程序运行时不允许出现的状况。
- Exception
- 在Exception分支中有一个重要的子类RuntimeException (运行时异常) ◆ArrayIndexOutOfBoundsException (数组下标越界) ◆NullPointerException (空指针异常) ◆ArithmeticException (算术异常) ◆MissingResourceException (丢失资源) ◆ClassNotFoundException (找不到类)等异常,
- 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
- 这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生;
- Error和Exception的区别: Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程; Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
-
异常处理框架
public class Demo1 {
public static void main(String[] args) {
int a=1;
int b=0;
//假设要捕获多个异常:从小到大!
try { //try监控区域
System.out.println(a/b);
} catch (Error e){ //catch(想要航获的异常类型! )捕获异常
System.out.println("Error");
} catch (Exception e){
System.out.println( "Exception");
} catch (Throwable t){
System.out.println("Throwable");
} finally { //处理普后工作
System.out.println( "finally");
}
//finally可以不要finally,假设IO, 资源,关闭!
}
public void a(){
b();
}
public void b(){
a();
}
}
- 主动抛出异常(ctrl+alt+t快捷键生成try...catch)
public class Demo02 {
public static void main(String[] args) {
try {
new Demo02().test( 1, 0);
} catch (ArithmeticException e) {
e. printStackTrace();
}
}
//假设这方法中,处理不了这个异常。方法上:抛出异常
public void test(int a,int b) throws ArithmeticException {
if (b == 0) { //throw
throw new ArithmeticException(); //主动的抛出异常,一般在方法中使用
}
System.out.println(a/b);
}
}
- 自定义异常
- 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
- 在程序中使用自定义异常类,大体可分为以下几个步骤:
- 创建自定义异常类。
- 在方法中通过throw关键字抛出异常对象。
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
- 在出现异常方法的调用者中捕获并处理异常。
public class Test {
static void test(int a) throws MyException{
System.out.println("details = "+a);
if (a>10){
throw new MyException(a);
}
System.out.println("ok");
}
public static void main(String[] args) {
try {
test(11);
} catch (MyException e) {
System.out.println("MyException-->"+e);
} finally {
}
}
}
public class MyException extends Exception{
private int detail;
public MyException(int a){
this.detail = a;
}
@Override
public String toString() {
return "MyException{"+detail+"}";
}
}
泛型
泛型类
泛型方法
泛型接口
类型通配符
可变参数
可变参数的使用
Java 枚举(enum)
Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
例如定义一个颜色的枚举类。
enum Color
{
RED, GREEN, BLUE;
}
以上枚举类 Color 颜色常量有 RED, GREEN, BLUE,分别表示红色,绿色,蓝色。
使用实例:
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
执行以上代码输出结果为:
RED
内部类中使用枚举
枚举类也可以声明在内部类中:
public class Test
{
enum Color
{
RED, GREEN, BLUE;
}
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
执行以上代码输出结果为:
RED
每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的。
以上的枚举类 Color 转化在内部类实现:
class Color
{
public static final Color RED = new Color();
public static final Color BLUE = new Color();
public static final Color GREEN = new Color();
}
迭代枚举元素
可以使用 for 语句来迭代枚举元素:
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
for (Color myVar : Color.values()) {
System.out.println(myVar);
}
}
}
执行以上代码输出结果为:
RED
GREEN
BLUE
在 switch 中使用枚举类
枚举类常应用于 switch 语句中:
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
}
}
执行以上代码输出结果为:
蓝色
values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Seriablizable 和 java.lang.Comparable 两个接口。
values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
public static void main(String[] args)
{
// 调用 values()
Color[] arr = Color.values();
// 迭代枚举
for (Color col : arr)
{
// 查看索引
System.out.println(col + " at index " + col.ordinal());
}
// 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentException
System.out.println(Color.valueOf("RED"));
// System.out.println(Color.valueOf("WHITE"));
}
}
执行以上代码输出结果为:
RED at index 0
GREEN at index 1
BLUE at index 2
RED
枚举类成员
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
enum Color
{
RED, GREEN, BLUE;
// 构造函数
private Color()
{
System.out.println("Constructor called for : " + this.toString());
}
public void colorInfo()
{
System.out.println("Universal Color");
}
}
public class Test
{
// 输出
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
c1.colorInfo();
}
}
执行以上代码输出结果为:
Constructor called for : RED
Constructor called for : GREEN
Constructor called for : BLUE
RED
Universal Color
枚举类中的抽象方法实现,需要枚举类中的每个对象都对其进行实现。
enum Color{
RED{
public String getColor(){//枚举对象实现抽象方法
return "红色";
}
},
GREEN{
public String getColor(){//枚举对象实现抽象方法
return "绿色";
}
},
BLUE{
public String getColor(){//枚举对象实现抽象方法
return "蓝色";
}
};
public abstract String getColor();//定义抽象方法
}
public class Test{
public static void main(String[] args) {
for (Color c:Color.values()){
System.out.print(c.getColor() + "、");
}
}
}
评论