(1)Java学习路线图(暑期阶段)
(2)常见cmd命令(输入法要用英文字符)
d: #转到D盘
dir #列出当前目录下的所有目录文件名字和文件名字
md class1 #在当前目录下创建一个叫做class1的文件夹
cd class1 #移动到叫做class1的文件夹里面去
cd class1/tech1 #移动到叫做class1的文件夹下面的tech1的文件夹里面去
cd .. #回退到上一个文件夹目录
rd class1 #删除文件夹class1
del 1.txt #删除1.txt这个文件
del *.txt #删除所有txt文件,del命令可以拓展文其他的文件
左右箭头移动,上下箭头可以找出用过的命令
(3)Java的一些基础知识
①Java平台分类
②Jre(Java运行环境)和JDK(下面为图解)
(1)JDK=Jre+java相关的开发工具(例如用于编译的javac)
(2)Jre=JVM(Java虚拟机)+Java SE标准类库
③Java运行的流程
(1)把Java代码编写在**.java结尾的源代码文件里面
(2)编译:用javac把源代码编译成字节码文件**,具体指令是javac helloword.java
(3)运行:用字节码文件运行,具体指令是java 字节码文件名
(4)变量与标识符
①变量
字符类型的使用方法
①使用单引号(’ ')括起来的:例如:char c1 = 'a'; char c2 = '中'; char c3 = '9';
②直接使用 Unicode值或者ACSII码来表示字符型常量:‘\uXXXX’。其中,XXXX 代表一个十六进制整数。例如:char c1=\u0023
表示 ‘#’。
③Java 中还允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。例如char c3 = '\n';
整型的使用方法
bool类型的使用方法
基本数据之间的类型转换
①自动类型提升:将取值范围小的类型自动提升为取值范围大的类型
具体情况是:①把取值范围小的值赋给取值范围大的值 ②许多取值范围的变量混合运算 ③当 byte,short,char 数据类型的变量进行算术运算时,按照 int 类型处理,例如byte b3 = b1 + b2;
编译报错,b1 + b2 自动升级为 int ,把结果赋给b3就不行。
②强制类型转换:将取值范围大的类型强制转换成取值范围小的类型,例如把3.14赋值给int,具体的方法是:数据类型 1 变量名 = (数据类型 1)被强转数据值; 例如int i = (int)3.14;
③任意八种基本数据类型的数据与 String 类型只能进行连接“+”运算,且结果一定也是 String 类型,String 类型不能通过强制类型()转换,转为其他的类型 ,要转换的话要用一些其他的办法:
int num = Integer.parseInt(str);
②运算符
(1)++i是先加再用,i++是先用再加(记忆法“++”在前面就是先加再用,反之陈丽)。单独运算没有区别,复合运算时候有区别;例如
int i=7,j=7;
int x=(++i)*5; x值为40
int y=(j++)*5; y值为35
PS:一种特殊情况此时m=2
(2)“+”的两种不同用法:
①对于+两边都是数值的话,+就是加法的意思 ;
②对于+两边至少有一边是字符串的话,+就是拼接;
(3) += 的操作不会改变变量本身的数据类型。其他拓展的运算符也如此,且有以下情况:
short s = 3;
s = s+2; 编译报错 ,因为2是int类型,s+2回自动转为int类型,int不可以赋值给short
s += 2;
(4)比较运算符的结果都是 boolean 型,也就是要么是 true,要么是 false。介绍一种一种新的比较运算符instanceof:用于查找某个变量是否是某个类的实例,用法是引用类型变量(object) instanceof 类(class)
boolean b1="Hello" instanceof String; b1一直是true
System.out.println(b1)
(5)一些逻辑运算符
(6)位运算符号
其中i>>5代表i除以32,i<<5代表i乘以32
,3<<4
类似于 3*2 的 4 次幂,右移是除法,左移是乘法(左乘右移)
(7)条件运算符int i = (1==2 ? 100 : 200); 此时i的值为200
。凡是可以使用条件运算符的地方,都可以改写为 if-else 结构。反之,不成立。 开发中,如果既可以使用条件运算符,又可以使用 if-else,推荐使用条件运算符。因为执行效率稍高。
该运算符可以用于实现找两数之间的最大值int max=i>j?i:j;
,
(3)一些语句
分支语句
在 switch 语句中,如果 case 的后面不写 break,将出现穿透现象,也就是一旦匹配成功,不会在判断下一个 case 的值,直接向后运行,直到遇到 break 或者整个 switch 语句结束,执行终止
int i = 3, test = 3;
switch (i) {
case 3:
test = test + 2;
case 2:
test = test + 2;
case 1:
test = test + 3;
}
此时test的值为10
循环语句
①for循环语句
代码如下所示:
②while 循环
③do-while 循环
最简单"无限"循环格式:while(true) , for(;;)
④Java的continue和break和C和C++相比多了一个优点:在多层嵌套的循环的时候可以通过标签指明要break或者continue
的是哪一层语句,如下所示:
而C和C++的这两个语句只可以对当前层的循环起作用
使用Scanner类进行输入
import java.util.Scanner; 导入Scanner包
class Main{
public static void main(String args[])
{
Scanner input=new Scanner(System.in);
//创建名为input的一个Scanner对象,参数是System.in
System.out.print("请输入意向输入的数字:");
int i=input.nextInt(); //调用input的nextInt()方法,还有很多别的next方法
System.out.println(i);
}
}
使用Math.random()产生随机数(不用import Math
)
数组
①数组的概念:是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。 下面是一维数组和二维数组的图示:
②数组的声明:在 Java 中数组的符号是[],[]表示一维,[][]表示二维。元素的类型可以是任意的 Java 的数据类型。例如:int、String、Student 等。Java 语言中声明数组时不能指定其长度(数组中元素的个数),必须用动态初始化才能确定。
int[] arr; //直接打印arr的话会打印出内存地址
int arr1[];
String[] arr3; //引用类型变量数组
int[][] grades; //存储多组姓名
String[][] names;//二维数组声明,直接打印name和name[i]的话会打印出内存地址
int[] x, y[]; //x 是一维数组,y 是二维数组
③数组的初始化
int array[]={0,1,2,3,4,5}; //静态初始化
int array[]=new int[5]; //动态初始化用于指定数组长度,里面是默认值
String[][] grade = {{"段誉","令狐冲","任我行"},{"张三丰","周芷若"},{"赵敏","张无忌","韦小宝","杨过"}}; //二维数组的静态初始化
int array[][]=new int[3][3];//二维数组的动态初始化
对于每一行的长度不一样的二维数组动态初始化的方法:先指定行数+为每一行分配空间
int array[][]=new int[3][]; //int array[][]=new int[][3]; 是违法的
array[0]=new int[2];
array[1]=new int[3];
array[2]=new int[4];
动态初始化的默认值如下:
④数组的遍历(利用数组名.length
直接获取所需数组的长度)
(1)一维数组
(2)二维数组
⑤Arrays 工具类的使用:java.util.Arrays 类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。Arrays类里的方法都是静态方法可以通过Arrays.方法名()
直接调用,比较经典的方法有:toString()//用于打印数组,sort(),equal(),binarySearch(),
import java.util.Scanner;
import java.util.Arrays;
class Main{
public static void main(String args[])
{
int array[]={2,4,1,3,5,10,7,9,8};
int array2[]={19,34,24,11,25,18};
String arr=Arrays.toString(array);//用于打印数组
Scanner input=new Scanner(System.in);
System.out.println("array经过toString转换而来的结果是"+arr);
Arrays.sort(array,0,array.length);//排序,左开右闭
for(int i=0;i<array.length;i++)
System.out.print(array[i]+" ");
System.out.println("\n请输入你想在array查找的数字:");
int i=input.nextInt();
int target=Arrays.binarySearch(array,i);
if(target<0) {
System.out.println("该元素不存在");
}
else {
System.out.println("待查找元素的下标是:"+target);
}
boolean flag=compare(array,array2);
if(flag) System.out.println("array和array2是一样的");
else System.out.println("array和array2是不一样的");
}
public static boolean compare(int arr1[],int arr2[])
{
boolean flag=Arrays.equals(arr1,arr2);//Arrays类里面用于比较数组的方法
return flag;
}
}
面向对象程序设计
(1)面向对象基础
①面向过程和面向对象之间的区别
②类的成员
③对象的相关内存知识
具体的如下所示:在Main方法当中创建对象,PS:p1 p2是引用类型,指向实际对象的内存首地址
所以可以根据该引用类型引入对象数组这一概念
④区分成员变量(声明在类内类方法外,存在对象实例的堆里面)和局部变量
⑤方法
(1)方法的声明:例如public int fibonacci(int n)
,目前和C++相比多了个修饰符和捕捉异常
(2)方法的参数
(3)方法重载:存在一个以上的同名方法,只要参数列表不一样就行
方法重载的两不同一同:只看名字和参数列表,这两个一样方法就一样,和返回值无关,
(4)可变参数个数的形参的方法:例子public int digui(int ... num)
(5)值传递机制
⑥package
和import
(1)package
:放在类文件的开头,用于指出该类文件所在的目录
具体使用如下所示:(可以看出package后面的地址正是RecursionTest所在的文件目录)
package的应用拓展:MVC设计模式
下列是JDK当中主要的包
(2)import:把其他包导入进来(告诉编译器该类文件的目录)
⑦封装:实现类方法和成员变量的可见性范围,先记住两个极端:protected
出了类不能用,public
都可以用
具体实例如下所示:
⑧构造器:new完对象以后可以直接赋值,并且构造方法可以构成方法重载
具体实例如下:
总结:给成员变量赋值的方法:
(2)面向对象进阶
①this关键字(this的意思就是指当前对象实例,用于调用当前类的方法和变量)
在实例方法或构造器中,如果使用当前类的成员变量或成员方法可以在其前面添加 this,增强程序的可读性。不过,通常我们都习惯省略 this。 但是,当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加 this 来表明该变量是类的成员变量。即我们可以用 this 来区分,如下所示:
也就是说有this修饰的话就是成员变量,没有this的话就是局部变量。this(形参列表)也可以用于实现同一个类内构造方法的重载。具体的情况如下所示:
①this():调用本类的无参构造器
②this(实参列表):调用本类的有参构造器
②继承:生活中的继承就是接受并且发扬光大,但在代码当中可以看成“抽取共性”
下面是Java当中的继承的一些相关知识
当子类的对象被创建的时候,会遵循以下情况:
子类不能直接访问父类当中private的成员变量和方法
③方法重写(Override):子类所继承的父类方法不能满足需求,需要对方法进行覆盖。
④super关键字:用于调用父类的成员变量和方法,和this一样用于防止名字混淆,还可以在方法进行重写之后再掉用父类的同名方法。
super也可以用super(形参列表)的形式用于调用父类的构造器来构建属于自己的构造器:
具体的如下所示:
下列是子类对象实例化的调用过程以及内存分析,(重点关注“找不到方法就跑到父类去找,知道找Object为止”这段过程):
super和this的一种理解就是:把super替换成直系父类的名字,this替换为当前类的名字
下列是二者的总结和上述知识的代码测试(两个类Mankind和Kids
):
public class Mankind {
int sex;
int salary;
public Mankind(){
}
public Mankind(int sex){
this();
this.sex=sex;
}
public Mankind(int sex,int salary){
this(sex);
this.salary=salary;
}
public void manOrwoman(){
if(this.sex==1) System.out.println("这个人类的性别是男");
else if(this.sex==0) System.out.println("这个人类的性别是女");
}
public void employee(){
if(this.salary==0) System.out.println("没有工作");
else System.out.println("有工作");
}
public void setsalary(int salary){
this.salary=salary;
}
public void setsex(int sex){
this.salary=sex;
}
}
public class Kids extends Mankind {
int yeasold;
public Kids(int sex,int salary,int yearsold){
super(sex,salary);
this.yeasold=yearsold;
}
public void printAge(){
System.out.println("这个孩子的年龄是:"+this.yeasold);
}
}
④多态:多态性,是面向对象中最重要的概念,在 Java 中的体现是对象的多态性:父类的引用指向子类的对象 。子类的对象可以替代父类的对象使用。所以,一个引
用类型变量可能指向(引用)多种不同类型的对象(既可以指向该类的对象实例也可以指向该类子类的对象实例)具体如下所示:
Mankind k1=new Kids(1,20000,10); // Mankind是Kids的父类
可以知道Kids确实是Mankind的一种,这样算是一种动态绑定,写代码更灵活
多态的好处和弊端如下:
①好处:变量引用的子类对象不同,执行的方法就不同,实现动态绑定。代码编写更灵活、功能更强大,可维护性和扩展性更好了。
②弊端:一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
接着多态的定义可以引入Java的虚方法调用:在 Java 中虚方法是指在编译阶段不能确定方法的调用入口地址,在运行阶段才能确定的方法,即可能被重写的方法。
Person e = new Student();
e.getInfo(); //调用 Student 类的 getInfo()方法
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。 如下所示:
PS:成员变量不具有这样的多态性,只有方法才满足这个性质。
因为“多态”会出现父类调用不了子类独有方法的情况,所以为了解决这问题引入了向上转型与向下转型 ,想要调用子类特有的方法,必须做类型转换,使得编译通过。具体的过程如下所示:
具体的代码示例如下所示:向下转型可以用 instanceof来判断是否可以这样转换。
Pet pet = new Dog(); //向上转型(向父类转型)自动实现
Dog dog1=(Dog)(pet); //向下转型(向子类转化)强制转换
⑤Object类:Java内所有类的父类,因此方法是通用的,也都可以重写。
Object 类当中包含的方法有 11 个。这里我们主要关注其中的 6 个:
①equals()
具体的代码为:p1.equals(p2),返回boolean类型如果p1==p2的话就返回true,不是的话返回false
下面是”==“和equals()方法的区别:
②toString() :默认情况下,toString()返回的是“对象的运行时类型 @ 对象的 hashCode 值的十六进制形式"
。在进行 String 与其它类型数据的连接操作时,自动调用 toString()方法,我们直接 System.out.println(对象)
,默认会自动调用这个对象的toString() 。因为 Java 的引用数据类型的变量中存储的实际上时对象的内存地址,但是 Java 对程序员隐藏内存地址信息,所以不能直接将内存地址显示出来,所以当你打印对象时,JVM 帮你调用了对象的 toString()。 可以根据需要在用户自定义类型中重写 toString()方法
③clone() :复制的作用,具体的代码如下:Animal a2 = (Animal) a1.clone();
④finalize() :当对象被回收时,系统自动调用该对象的 finalize() 方法。永远不要主动调用某个对象的 finalize 方法,应该交给垃圾回收机制调用。当某个对象没有任何引用时,JVM 就认为这个对象是垃圾对象,就会在之后不确定的时间使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize()方法。 子类可以重写该方法,目的是在对象被清理之前执行必要的清理操作。比如,在方法内断开相关连接资源
⑤getClass():获取对象的运行时类型
⑥ hashCode():返回每个对象的 hash 值
(3)面向对象高级
①static关键字:如果想让一个成员变量被类的所有实例所共享,就用 static 修饰即可,称为类变量(或类属性)。无论产生了多少对象,某些特定的数据在内存空间里只有一份。
静态变量的一些特点:
静态变量的内存分析(以一个Chinense类为例子,nation为静态变量,其在方法区,可供所有对象实例共享):
class Chinese{
//实例变量
String name;
int age;
//类变量
static String nation;//国籍
public Chinese() {
}
public Chinese(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Chinese{" +
"name='" + name + '\'' +
", age=" + age +
", nation='" + nation + '\'' +
'}';
}
}
同样,有static关键字修饰的方法就被称为静态方法,这里方法可以此类方法有着以下的特点:
静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
①只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也
可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。
②在 static 方法内部只能访问类的 static 修饰的属性或方法,不能访问非 static 的结构。
③静态方法可以被子类继承,但不能被子类重写。
④静态方法的调用都只看编译时类型。
⑤因为不需要实例就可以访问 static 方法,因此 static 方法内部不能有 this,也不能有
super。如果有重名问题,使用“类名.”进行区别。下面是直接调用静态方法的代码案例:
Chinese.self_introduction(); //就是这个时候当把Chinese类加载进来
public class Chinese { //此时static修饰的静态代码块在加载进来的时候执行
private static String country;
private String name;
static {
country = "中国";
System.out.println("静态代码块");
}
public static void self_introduction(){
System.out.println("I am chinese");
}
}
②代码块:用于初始化类的变量等等
(1)静态代码块:代码块的前面加 static,就是静态代码块,类加载的时候执行,具体的如下所示:
(2)非静态代码块:每次创建对象实例的时候,都会执行一次。且**先于构造器执行。**具体的格式以及特点如下所示:
以下是给实例变量赋值的顺序:
③final关键字
(1)final 修饰类:表示这个类不能被继承,没有子类。提高安全性,提高程序的可读性。 例如:String 类、System 类、StringBuffer 类 ,具体如下:
final class Eunuch{//太监类
}
class Son extends Eunuch{//错误
}
(2)final 修饰方法:表示这个方法不能被子类重写。下个例子中method
不能被重写
class Father{
public final void method(){
System.out.println("father");
}
}
class Son extends Father{
public void method(){//错误
System.out.println("son");
}
}
(3)final 修饰某个变量(成员变量或局部变量):一旦赋值,它的值就不能被修改,即常量,常量名建议使用大写字母。 final的赋值方法有三种:显示赋值,构造器赋值和代码块赋值。
④抽象类与抽象方法( abstract 关键字)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类(例如下面的几何图形类,根本无法创建对象)。
我们声明一些几何图形类:圆、矩形、三角形类等,发现这些类都有共同特征:求面积、求周长。那么这些共同特征应该抽取到一个共同父类:几何图形类中。但是这些方法在父类中又无法给出具体的实现,而是应该交给子类各自具体实现(也就是重写)。那么父类在声明这些方法时,只有方法签名,没有方法体,我们把没有方法体的方法称为抽象方法。
抽象类和抽象方法的具体的代码声明如下:
下面是二者的一些特征:
PS:不能用 abstract 修饰变量、代码块、构造器; 不能用 abstract 修饰私有方法、静态方法、final 的方法、final 的类。
下面是抽象类的一次实际的代码练习:
public abstract class human {
String name;
String xingbie;
public human(String name,String xingbie){
this.name=name;
this.xingbie=xingbie;
}
public abstract void eat();
}
public class China extends human{
public China(String name,String xingbie){
super(name,xingbie);
}
public void eat(){
System.out.println(name+"用筷子吃饭");
}
}
public class America extends human{
public America(String name,String xingbie){
super(name,xingbie);
}
public void eat(){
System.out.println(name+"用刀叉吃饭");
}
}
America A=new America("Lisa","girl");
China C=new China("Mayun","boy");
A.eat();
C.eat();
运行的结果如下:
④接口(interface)也就是implement关键字:接口就是规范,定义的是一组规则,体现了现实世界中**“如果你是/要…则必须能…”的思想。继承是一个"是不是"的 is-a 关系,而接口现则是 "能不能"的has-a 关系**,具体的如下所示:
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class 文件,但一定要明确它并不是类,而是另外一种引用数据类型。接口的定义方式如下图所示:
public interface USB3{
//静态常量
long MAX_SPEED = 500*1024*1024;//500MB/s
//抽象方法
void in();
void out();
//默认方法
default void start(){
System.out.println("开始");
}
default void stop(){
System.out.println("结束");
}
//静态方法
static void show(){
System.out.println("USB 3.0 可以同步全速地进行读写操作");
}
}
接口的使用规则如下:
①类实现接口(类似于把接口安在类上面):接口不能创建对象,但是可以被类实(implements ,类似于被继承)。 类与接口的关系为实现关系,即类实现接口。如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法。默认方法可以选择保留,也可以重写。 接口中的静态方法不能被继承也不能被重写对于接口的静态方法,直接使用“接口名.”进行调用即可,不能通过实现类的对象进行调用。对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用 。
②接口的多实现(implements):之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
③接口的多继承(extends): 一个接口能继承另一个或者多个接口,接口的继承也使用 extends 关键字,子接口继承父接口的方法
⑤内部类:具体来说,当一个事物 A 的内部,还有一个部分需要一个完整的结构 B 进行描
述,而这个内部的完整的结构 B 又只为外部事物 A 提供服务,不在其他地方单独使用,那么整个内部的完整结构 B 最好使用内部类。 内部类也有分类:
(1)成员内部类:如果成员内部类中不使用外部类的非静态成员,那么通常将内部类声明为静态内部类,否则声明为非静态内部类。语法的格式如下:
成员内部类的使用特征,概括来讲可以作为类的内部成员和一个真正的类来说明:
成员内部类的代码调用如下图所示:
①静态内部类 (StaticInner
是Outer
的内部类)
//创建静态内部类实例,并调用方法
Outer.StaticInner inner = new Outer.StaticInner();
inner.inFun();
//调用静态内部类静态方法
Outer.StaticInner.inMethod();
②非静态内部类(这个要先实例化外部类,①不用)
//创建非静态内部类实例(方式 1),并调用方法
Outer outer = new Outer();
Outer.NoStaticInner inner1 = outer.new NoStaticInner();
inner1.inFun();
//创建非静态内部类实例(方式 2)
Outer.NoStaticInner inner2 = outer.getNoStaticInner();
inner1.inFun();
(2)局部内部类:又称“方法内部类”,就是定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其有效范围只限于方法内部。 在局部内部类中,局部内部类可以访问外部类的所有成员变量和方法。具体的可分为两种:
①非匿名内部类:
这种类的特点如下:
②匿名内部类:因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。 最本质的还是一个类,是一个内部类,该类没有名字(但是系统会分配一个代号在内存中)。以下面的那个应用场景作例子:正常的话是声明一个内部类来实现接口A,这样的话太过啰嗦。直接匿名类的话会节省很多步骤:
⑤枚举类:枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。枚举类的例子举不胜举, 例如星期:Monday到Sunday。
下列是JDK5之前定义枚举类的方法:
public class Season {
private final String SEASONNAME;//季节的名称
private final String SEASONDESC;//季节的描述
private Season(String seasonName,String seasonDesc){
this.SEASONNAME = seasonName;
this.SEASONDESC = seasonDesc;
}
//固定的几个对象实例
public static final Season SPRING = new Season("春天", "春暖花开 ");
public static final Season SUMMER = new Season("夏天", "夏日炎炎 ");
public static final Season AUTUMN = new Season("秋天", "秋高气爽 ");
public static final Season WINTER = new Season("冬天", "白雪皑皑 ");
public void output(){
System.out.println("季节的名称是"+this.SEASONNAME);
System.out.println("季节的描述是"+this.SEASONDESC);
}
}
实现的方式就是:①构造方法私有化 ②在类里面声明几个固定的对象实例可以直接调用,例如Season.AUTUMN.output();
JDK5之后的方法就是使用enum
关键字,和上面枚举类的等价具体的如下所示:
public enum Season {
//这几个都是常量,注意最后一个是分号,其余的是逗号
SPRING("春天", "春暖花开 "),
SUMMER("夏天", "夏日炎炎"),
AUTUMN("秋天", "秋高气爽"),
WINTER("冬天", "无比寒冷");
//下面是Season的属性
private final String SEASONNAME;//季节的名称
private final String SEASONDESC;//季节的描述
private Season(String seasonName,String seasonDesc){
this.SEASONNAME = seasonName;
this.SEASONDESC = seasonDesc;
}
public void output(){
System.out.println("季节的名称是"+this.SEASONNAME);
System.out.println("季节的描述是"+this.SEASONDESC);
}
}
并且enum还可以实现接口,但是每一个常量都要实现接口里面的所有的抽象方法,具体的如下所示(区别仅仅在于提供固定常量实例那里而已):
interface Info{
void show();
}
enum Season1 implements Info{
//1. 创建枚举类中的对象,声明在 enum 枚举类的首位
SPRING("春天","春暖花开"){
public void show(){
System.out.println("春天在哪里?");
}
},
SUMMER("夏天","夏日炎炎"){
public void show(){
System.out.println("宁静的夏天");
}
},
AUTUMN("秋天","秋高气爽"){
public void show(){
System.out.println("秋天是用来分手的季节");
}
},
WINTER("冬天","白雪皑皑"){
public void show(){
System.out.println("2002 年的第一场雪");
}
};
//剩下的和上面一样
⑥包装类:Java 针对八种基本数据类型定义了相应的引用类型:包装类(封装类)。有了
类的特点,就可以调用类中的方法,Java 才是真正的面向对象。
内存结构对比如下图所示:
下面是包装类的一些常用的方法:
在这里插入代码片
String类型
(1)String的特性
String str1 = “abc”
与 String str2 = new String(“abc”)
这两句话也是有区别的,具体的如下:
具体的表现如下:
(2)intern() 方法
(3)String 的常用 API
①构造器
具体代码如下:
//字面量定义方式:字符串常量对象
String str = "hello";
//构造器定义方式:无参构造
String str1 = new String();
//构造器定义方式:创建"hello"字符串常量的副本
String str2 = new String("hello");
//构造器定义方式:通过字符数组构造
char chars[] = {'a', 'b', 'c','d','e'};
String str3 = new String(chars);
String str4 = new String(chars,0,3);
//构造器定义方式:通过字节数组构造
byte bytes[] = {97, 98, 99 };
String str5 = new String(bytes);
String str6 = new String(bytes,"GBK");
②常用方法
③用于查找的方法:
(11)boolean contains(xx):
是否包含 xx
(12)int indexOf(xx):
从前往后找当前字符串中 xx,即如果有返回第一次出现的下标,要是没有返回-1
(13)int indexOf(String str, int fromIndex):
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
(14)int lastIndexOf(xx):
从后往前找当前字符串中 xx,即如果有返回最后一次出现的下标,要是没有返回-1
(15)int lastIndexOf(String str, int fromIndex):
返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
④字符串截取:
⑤开头与结尾 :
⑥替换
(4)可变字符序列:StringBuffer、StringBuilder
因为 String 对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低,空间消耗也比较高。因此,JDK 又在 java.lang包提供了可变字符序列 StringBuffer 和 StringBuilder 类型。具体对比如下:
//情况 1:
String s = new String("我喜欢学习");
//情况 2:
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer.append("数学");
StringBuilder、StringBuffer 的 API
此外JAVA还有一些用于日期的API例如:java.lang.System 类的方法,java.util.Date ,java.text.SimpleDateFormat,java.util.Calendar(日历)
Java 比较器
Java 实现对象排序的方式有两种:
– 自然排序:java.lang.Comparable
– 定制排序:java.util.Comparator
(1)java.lang.Comparable :继承Comparable并实现CompareTo方法,可以说是在类内部就定好了排序的方式
具体代码如下:
public class STU implements Comparable{
private int id;
private String name;
private int score;
private int age;
public STU(int id, String name, int score, int age) {
this.id = id;
this.name = name;
this.score = score;
this.age = age;
}
//可以根据这个调换顺序
public int compareTo(Object o){
return ((STU)o).id-this.id;
}
//重写这个方法用于每个对象的信息
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
", id="+id+
",age="+age+
'}';
}
}
STU[] arr = new STU[5];
arr[0] = new STU(3, "张三", 90, 23);
arr[1] = new STU(1, "熊大", 100, 22);
arr[2] = new STU(5, "王五", 75, 25);
arr[3] = new STU(4, "李四", 85, 24);
arr[4] = new STU(2, "熊二", 85, 18);
Arrays.sort(arr);//直接用sort函数排序就行
(2)java.util.Comparator :专门写一个 Comparator类用于控制排序,可以把Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
重写 compare(Object o1,Object o2)方法,具体的代码如下:
public class STU implements Comparable{
private int id;
private String name;
private int score;
private int age;
public STU(int id, String name, int score, int age) {
this.id = id;
this.name = name;
this.score = score;
this.age = age;
}
//可以根据这个调换顺序
public int compareTo(Object o){
return ((STU)o).id-this.id;
}
//重写这个方法用于每个对象的信息
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
", id="+id+
",age="+age+
'}';
}
}
//定义一个实现Comparator接口的类
public class StudentScoreComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
int result = s1.getScore() - s2.getScore();
return result != 0 ? result : s1.getId() - s2.getId();
}
}
//
Student[] students = new Student[5];
students[0] = new Student(3, "张三", 90, 23);
students[1] = new Student(1, "熊大", 100, 22);
students[2] = new Student(5, "王五", 75, 25);
students[3] = new Student(4, "李四", 85, 24);
students[4] = new Student(2, "熊二", 85, 18);
System.out.println(Arrays.toString(students));
//定制排序 ,就把这个类的实例传入sort函数即可
StudentScoreComparator sc = new StudentScoreComparator();
Arrays.sort(students, sc);
PS:使用if-else语句还可以实现基于多个变量的综合排序。比如STU对象排列综合优先考虑score而后考虑id,则可以计算s1.score-s2.score
,要是不等于0直接返回,等于0的话返回s1.id-s2.id
Java 集合框架
(1)Collection(集合) 接口及方法
具体的方法代码如下所示:
import java.util.ArrayList;
import java.util.Collection;
//添加
(1) add():添加一个单独的元素
Collection coll = new ArrayList();
coll.add("小李广");
coll.add("扫地僧");
coll.add("石破天");
System.out.println(coll);
(2)addall():把一个集合直接添加过来
coll2.addAll(coll);
//判断
int size():获取当前集合中实际存储的元素个数
boolean isEmpty():判断当前集合是否为空集合
boolean contains(Object obj):判断集合中是否存在一个与 obj 对象相同的元素
boolean containsAll(Collection coll):即 coll 集合是否是当前集合的“子集”
boolean equals(Object obj):判断当前集合与 obj 是否相等
//删除
void clear():清空集合元素
boolean remove(Object obj) :从当前集合中删除第一个找到的与 obj 对象 一样的元素。
boolean removeAll(Collection coll):从当前集合中删除所有与 coll 集合中相同的元素。
即 this = this - this ∩ coll
boolean retainAll(Collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与 coll 集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即 this = this ∩ coll;
//
(2)Iterator(迭代器)接口
Iterator iterator = coll.iterator(); //默认指向coll的第一个元素
System.out.println(iterator.next()); //指向第二个,每次调用next方法得到一个全新迭代器
System.out.println(iterator.next()); //指向第三个元素
System.out.println(iterator.next()); //指向第四个元素
iterator.remove(); //删除iterator所指向的元素,这样可以根据条件删除
(3)foreach 循环:一种高级的用于遍历数组和集合
foreach循环其实就是使用 Iterator 迭代器来完成元素的遍历的
PS:上面用Object就是万能的,用其他可能报错。具体的如下:
//遍历集合
Collection coll = new ArrayList();
coll.add("小李广");
coll.add("扫地僧");
coll.add("石破天");
for (Object o : coll) {
System.out.println(o);
}
//遍历数组
int[] nums = {1,2,3,4,5};
for (int num : nums) {
System.out.println(num);
}
String[] names = {"张三","李四","王五"};
for (String name : names) {
System.out.println(name);
}
(4)Collection 子接口List
List 接口的实现类常用的有:ArrayList、LinkedList 和 Vector。 List 除了从 Collection 集合继承的方法外,List 集合里添加了一些根据索引来操作集合元素的方法。
(5)Collection 子接口 Set
Set 主要实现类:HashSet