JavaBasic
- 创建的文件名需与类名一致,即
HelloWorld.java
,严格要求大小写。
- 主函数参数可为
String args[]
与
String[] args
。
- 一个源文件只能有一个
public
类,且仅为文件名相同的类为
public
属性。
-
java
文件运行是
javac
将
Hello.java
文件编译成
Hello.class
的字节码,然后由
jvm
虚拟机对其进行解释执行。
public class HelloWorld{public static void main(String[] args){System.out.println("Hello World")}}
访问控制符
-
private
,
default
,
protected
,
public
四个标识符。| | 同一个类中 | 同一个包中 | (不同包)子类中 | 全局范围内 || — | — | — | — | — || private | ✓ | | | || default | ✓ | ✓ | | || protected | ✓ | ✓ | ✓ | || public | ✓ | ✓ | ✓ | ✓ |
private
private
只允许当前类进行访问,继承也无法访问。
public class AccessControlStudy {private int age = 18;public String name = "Pan3a";protected String love = "java";private void sayAge(){System.out.println("age:" + Integer.toString(this.age) );}public void sayName(){System.out.println("name:" + this.name);}protected void sayLove(){System.out.println("love:" + this.love);}}class Test extends AccessControlStudy{}class PrivateStudy{public static void main(String[] args) {AccessControlStudy ac = new AccessControlStudy();Test test = new Test();// ac.sayAge();// test.sayAge();// 因为private原因,直接无法编译。子类和实例化对象都无法访问。ac.sayName();test.sayName();ac.sayLove();test.sayLove();}}
default
- 只能是同一个类或同一个包中访问。
package com.Pan3a.DefaultStudy;public class AccessControlStudy{String name = "Pan3a";}
- 不同的另外一个包
package com.Pan3a.Class;public class AccessControlStudyThree {String name = "Pan3a";public void SayName(){System.out.println("Hello " + this.name);}}
- 测试文件
package com.Pan3a.DefaultStudy;import com.Pan3a.Class.AccessControlStudyThree;public class AccessControlStudyTwo {public static void main(String[] args) {// 同一个包中的default可以使用com.Pan3a.DefaultStudy.AccessControlStudy ac = new com.Pan3a.DefaultStudy.AccessControlStudy();System.out.println(ac.name);// 不同包中com.Pan3a.Class.AccessControlStudyThree three = new AccessControlStudyThree();// System.out.println(three.name);// 因为在不用包中因此调用时语法错误无法编译// 因为访问的是AccessControlStudyThree中的SayName方法,变量是实例化的类中因此可访问three.SayName();}}
protected
- 同一个类或同一个包或不同包中子类访问。
package com.Pan3a.DefaultStudy;public class AccessControlStudy{protected String name = "Pan3a";}
- 不同包中
package com.Pan3a.Class;public class AccessControlStudyThree {protected String name = "Pan3a";public void SayName(){System.out.println("Hello " + this.name);}}
-
protected
属性访问用继承式。
package com.Pan3a.DefaultStudy;import com.Pan3a.Class.AccessControlStudyThree;class ProtectedStudy extends AccessControlStudyThree{ProtectedStudy(){System.out.println("Hello " + super.name);}}public class AccessControlStudyTwo {public static void main(String[] args) {// 同一个包中的default可以使用com.Pan3a.DefaultStudy.AccessControlStudy ac = new com.Pan3a.DefaultStudy.AccessControlStudy();System.out.println(ac.name);// 不同包中com.Pan3a.Class.AccessControlStudyThree three = new AccessControlStudyThree();// System.out.println(three.name);// 因为在不用包中因此调用时语法错误无法编译// 虽然是不同包中,但是这里可以通过继承的来访问ProtectedStudy protectedStudy = new ProtectedStudy();// 因为访问的是AccessControlStudyThree中的SayName方法,变量是实例化的类中因此可访问three.SayName();}}
public
- 适用于任何情况,但实际项目仍需手动指定属性。
字符 && 字符串
- 字符用
\'P\'
这样的单引号进行包裹。
- 字符串用
"Hello World"
这样的双引号进行包裹。
字符数组
- 字符数组
public class CharStudy{}public static void main(String[] args){char[] HelloArray = {\'H\',\'e\',\'l\',\'l\',\'o\'};String HelloString = new String(HelloArray);System.out.println(HelloString);System.out.println(HelloString + "字符长度为:" + HelloArray.length);}}
创建字符串
public class StringStudy{public static void main(String[] args){// 会创建一个匿名对象String stringOne = "Hello";System.out.println(stringOne);// 构造函数创建字符串String stringTwo = new String("Pan3a");System.out.println(stringTwo);// 字符串拼接String stringThree = "Hello " + stringTwo;System.out.println(stringThree);// 字符对比String stringFour = stringOne.concat(stringTwo);String stringFive = stringOne + stringTwo;String stringSix = "Hello Pan3a";// 这里的 == 是比较内存中存放的首地址 equals 则是比较字符是否相同if(stringSix == stringFour){System.out.println("OK");}if(stringSix.equals(stringFour)){System.out.println("OK2");}}}
格式化字符串
- 格式化数字可以用
printf()
和
format()
方法。
-
format()
返回一个
String
对象而不是
PrintStream
,可以创建一个可复用的格式化字符串。
public class StringStudy{public static void main(String[] args){int intVar = 1;String stringVar = "Hello World";System.out.printf("整型变量:" + "%d" + " 字符串变量:%s" + "\\n",intVar,stringVar);String fs;fs = String.format("整型变量:" + "%d" + " 字符串变量:%s",intVar,stringVar);System.out.println(fs);}}
StringBuffer && StringBuilder
- 这里的
StringBuffer
和
StringBuilder
来由是因为平常创建的字符串在修改的时候是重新创建的一个对象,而不是原字符串。后者没有线程安全,但是相比前者后者有速度优势,因此大多数情况下建议使用后者。
public class StringStudy{public static void main(String[] args){StringBuilder sb = new StringBuilder(10);sb.append("Hello World");System.out.println(sb);for(int num=0;num<sb.length();num++){System.out.println(sb.charAt(num));}// 这里实例化类会将字符进行一次输出StringBuffer sBuffer = new StringBuffer("Hello Pan3a");sBuffer.append("你好,");sBuffer.append("Pan3a");System.out.println(sBuffer);}}
数组
- 数组的遍历
public class ArrayStudy {public static void main(String[] args) {// 数组大小int size = 10;int[] myList = new int[size];for (int num=0;num<size;num++){myList[num] = size-(num+1);System.out.println(Integer.toString(num) + " " + myList[num]);}// 加强型循环for (int value:myList){System.out.println(value);}}}
日期时间
- 有时候需要查看当前时间并且格式化输出。
import java.text.SimpleDateFormat;import java.util.Date;public class DateStudy {public static void main(String[] args) {Date date = new Date();SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");System.out.println(date.getTime());System.out.println(date.toString());System.out.println("当前时间:" + ft.format(date));System.out.printf("年-月-日:%tF%n",date);}}
正则表达式
- 正则处理文本。
import java.util.regex.Matcher;import java.util.regex.Pattern;public class ReStudy {public static void main(String[] args) {String info = "My name is Pan3a,I am from China";String pattern = ".*Pan3a.*";boolean isMatch = Pattern.matches(pattern,info);System.out.println("字符是否包含 \'Pan3a\' ?" + isMatch);}}
I/O
- 平常接触多的应该就算文件的操作了。
File
- 创建文件有个临时文件,删除文件
import java.io.*;public class FileStudy{public static void main(String[] args) throws IOException{String filePath = "C:\\CodeProject\\JavaStudy\\src\\Flag";File file = new File(filePath);System.out.println(file);// 返回构造方法传入的路径// System.out.println(file.getPath());// 返回绝对路径// System.out.println(file.getAbsolutePath());// 类似于绝对路径,但是更规范// System.out.println(file.getCanonicalPath());if(file.isFile()){System.out.println(file.getAbsoluteFile() + " 这是一个文件");// 判断文件是否可读if(file.canRead()){System.out.println(file.getAbsoluteFile() + " 文件可读");}else {System.out.println(file.getAbsoluteFile() + " 文件不可读");}// 判断文件是否可写if (file.canWrite()){System.out.println(file.getAbsoluteFile() + " 文件可写");}// 判断文件可执行if(file.canExecute()){System.out.println(file.getAbsoluteFile() + " 文件可执行");}}File tempFile = File.createTempFile("tmp",".txt");if(tempFile.isFile()){System.out.println(tempFile.getAbsoluteFile() + " 临时文件创建成功");tempFile.deleteOnExit();System.out.println(tempFile.getAbsolutePath());}}}
目录
- 和文件类似,多的是目录中的文件和目录遍历,目录删除时无法删除非空目录。
import java.io.*;public class FileStudy{public static void main(String[] args) throws IOException{// 创建目录File createDir = new File("Hello");// File createDirs = new File("Hello/Hello/Hello");// if(createDirs.mkdirs()) 这里mkdirs 可以创建没有的父目录if(createDir.mkdir()){System.out.println("OK");if(createDir.delete()){// 这里的删除只能删除非空的目录System.out.println(createDir.getAbsolutePath() + " 文件删除成功");}}String dirPath = "C:\\\\windows";File dir = new File(dirPath);File[] dirs = dir.listFiles(new FilenameFilter() {// 重载方法,过滤不需要的文件@Overridepublic boolean accept(File dir, String name) {return name.endsWith(".exe");}});// for (int i=0;i<dirs.length;i++){// System.out.println(dirs[i]);// }for (File f:dirs){System.out.println(f);}}}
InputStream
- 所有与IO操作相关的代码都必须正确处理
IOException
,否则无法正常运行。
- 读取文本是字节或字符串。
import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class InputStreamStudy {public static void readFile() throws IOException{try(InputStream inputStream = new FileInputStream("c://CodeProject//JavaStudy//src//Flag")){int n;while ((n = inputStream.read()) != -1){System.out.println((char) n);}}}public static void readFileBuffer() throws IOException{try(InputStream inputStream = new FileInputStream("c://CodeProject//JavaStudy//src//Flag")){byte[] buffer = new byte[1000];int n;while ((n = inputStream.read(buffer)) != -1){System.out.println("read " + n + " bytes");}}}public static String readFileAsString(InputStream inputStream) throws IOException{int n;StringBuilder stringBuilder = new StringBuilder();while ((n = inputStream.read()) != -1){stringBuilder.append((char) n);}return stringBuilder.toString();}public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("c://CodeProject//JavaStudy//src//Flag");for (;;){int n = inputStream.read(); // 反复读取if(n == -1){break;}System.out.println(n); // 打印的byte的值}inputStream.close();// 如果代码出错,并不会回收输入流,可用tryreadFile();// 一次读取一个字节不高效,因此可以使用缓冲readFileBuffer();// 读取文本字符String string;try(InputStream input = new FileInputStream("c://CodeProject//JavaStudy//src//Flag")){string = readFileAsString(input);}System.out.println(string);}}
OutputStream
- 文件写入,没看到追加
import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;public class OutputStreamStudy {public static void main(String[] args) throws IOException{String fileName = "c:\\\\CodeProject\\\\JavaStudy\\\\src\\\\Flag";try(OutputStream outputStream = new FileOutputStream("c:\\\\CodeProject\\\\JavaStudy\\\\src\\\\Flag")){outputStream.write("Hello Pan3a".getBytes("UTF-8"));}}}
Scanner
- 推荐
hasNextLine
方法,直接获取全部数据,
hasNext
无法获取空格,认为其是结束符。
import java.util.Scanner;public class ScannerStudy {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("next方法接收:");// 判断是否还有输入if(scanner.hasNext()){String stringOne = scanner.next();System.out.println("输入的数据为:" + stringOne);}scanner.close();Scanner scan = new Scanner(System.in);System.out.print("nextLine方式接收:");if(scan.hasNextLine()){String stringTwo = scan.nextLine();System.out.println("输入的数据为:" + stringTwo);}System.out.print("请输入数字:");int count = 0;double sum = 0;while (scan.hasNextDouble()){double number = scan.nextDouble();count += 1;sum += number;}System.out.println("一共" + Integer.toString(count) + "个数");System.out.println("和为" + sum);scan.close();}}
异常处理
面向对象
方法
- 主要是结合访问控制符和参数传递来实现特定功能。
class Person{String[] name = {};public Person(String... names){for(String name:names){System.out.println("构造方法可变参数: " + name);}this.name = names;}public void getName(){for (String name:this.name) {System.out.print(name + " ");}}public void setName(String[] names){for (String setName:names){System.out.println("数组类型参数: " + setName);}this.name = names;}}public class ObjectFunc {public static void main(String[] args) {String[] names = {"Pan3a","Forever404"};// 构造方法实例化Person personOne = new Person(names);// 数组参数personOne.setName(names);// 参数传递 指向的是原变量地址 改变变量实质变量名不变地址为新地址---新对象String name = "Pan3a";Person personTwo = new Person(name);personTwo.getName();name = "Forever404";personTwo.getName();// 参数传递 数组地址没改变 改变的是地址中存的值String[] color = {"RED","BLUE"};Person personThree = new Person(color);personThree.getName();color[0] = "GREEN";System.out.println();personThree.getName();}}
构造方法
- 每个类都有构造方法,没有则Java编译器将会提供一个默认的构造方法。构造方法需与类同名,一个类可以有多个构造方法。
- 构造方法类似于
Python
的
__init__(self)
主要作用于类的初始化。
package com.pan3a.test;public class ObjectConstruct {public static void main(String[] args) {Person personOne = new Person();System.out.println(personOne.getName());System.out.println(personOne.getAge());Person personTwo = new Person("Pan3a",20);System.out.println(personTwo.getName());System.out.println(personTwo.getAge());Person personThree = new Person("Forever404");System.out.println(personThree.getName());System.out.println(personThree.getAge());}}class Person{protected String name;protected int age;// 无参数构造方法,会自动创建,默认的构造方法public Person(){}// 重载此构造方法,实例化类时根据传递参数自动选择构造方法public Person(String name,int age){this.name = name;this.age = age;}// 构造方法调用其他构造方法public Person(String name){this(name,18);}public String getName(){return this.name;}public int getAge(){return this.age;}}
方法重载
- 方法名相同,参数不同,返回值相同。
- overload,重载,相当于重新写了一个方法,但是这些方法都不同,因为它们的参数都不一样。
package com.pan3a.hello;public class ObjectOverload {public static void main(String[] args) {Person personOne = new Person();personOne.hello();personOne.hello("Pan3a");personOne.hello("Pan3a",16);personOne.hello("Pan3a",20);}}class Person{public void hello(){System.out.println("Hello World");}public void hello(String name){System.out.println("Hello " + name);}public void hello(String name,int age){if (age > 18){System.out.println("Hello " + name + ", you are an adult!");}elseSystem.out.println("Hello " + name + ", you are a child!");}}
继承
- 子类无法继承父类的构造方法
- 子类的构造方法必须与父类的构造方法类型一致 如:无参对应无参
- 子类的构造方法第一条语句必须是父类构造方法
- 只能单继承,除Object外没有关键字
extends
的类都是继承于
Object
- Java15特性,
sealed
于
permits
修饰的类只能在指定的类继承
- Java继承还有向上转型和向下转型两种。
sealed class Color permits Red,Blue,Green{}
package com.pan3a.extend.up;public class ObjectExtendsUp {public static void main(String[] args) {// 向上转型 因为继承关系 Student->Person->Object Student有Person的全部属性Person personOne = new Student();System.out.println(personOne.name);System.out.println(personOne.age);}}class Person{public String name = "Pan3a";public int age = 18;}class Student extends Person{}
package com.pan3a.extend.up;public class ObjectExtendsUp {public static void main(String[] args) {// 向下转型 也是由于继承关系 但父类无法转为子类 因为子类有父类没有的属性Person p1 = new Student();Person p2 = new Person();// Student s2 = (Student) p2; 这里会由于实例化的Person,但变量类型是Student,变量类型中有Person中没有的属性因此会失败if(p1 instanceof Student){Student s1 = (Student) p1;}}}class Person{public String name = "Pan3a";public int age = 18;}class Student extends Person{}
package com.pan3a.extend;public class ObjectExtends {public static void main(String[] args) {// Student studentPan3a = new Student("Pan3a",18,60);Student studentPan3a = new Student();System.out.println(studentPan3a.getAge());System.out.println(studentPan3a.getName());System.out.println(studentPan3a.getScore());studentPan3a.setScore(99);System.out.println(studentPan3a.getScore());}}class Person{protected String name;protected int age;public Person(String name,int age){this.name = name;this.age = age;}public Person() {}public void setName(String name){this.name = name;}public String getName() {return name;}public void setAge(int age){this.age = age;}public int getAge(){return age;}}class Student extends Person{private int score;public Student(String name,int age,int score){// 子类构造方法必须先调用父类构造方法super(name,age);this.score = score;}// 这里子类的构造方法必须与父类对应 如:无参对应无参public Student(){super();}public void setScore(int score){this.score = score;// System.out.println("Score has change:" + Integer.toString(score));}public int getScore(){return this.score;}}final class Animal{}/*这里就无法继承Animal类,因为此类用了final关键字进行修饰class Teacher extends Animal{}*/
方法重写
- Overrie,都是同一个方法,类型参数都一样,只不过实现功能有所更改。
package com.pan3a.override;public class ObjectOverride {public static void main(String[] args) {Student studentOne = new Student();studentOne.hello();}}class Person{public void hello(){System.out.println("Hello");}}class Student extends Person{@Overridepublic void hello(){super.hello();System.out.println("Hello World!");}}
多态
- 根据不同类自动执行不同的方法,动态调用。
package com.pan3a.polymorphism;public class ObjectPolymorphism {public static void running(Person p){p.run();}public static void main(String[] args) {running(new Person());running(new Student());}}class Person{public void run(){System.out.println("Person run");}}class Student extends Person{@Overridepublic void run(){System.out.println("Student run");}}
- 具体例子,多态就会自动选择实例类型。
public class ObjectPolymorphismDemo{public static void main(String[] args){// 一个有普通收入 工资收入 国家补贴的人计算税Income[] incomes = new Income[]{new Income(3000),new Salary(7500),new StateCouncilSpecialAllowance(15000)};System.out.println(totalTax(incomes));}public static double totalTax(Income... incomes){double total = 0;for (Income income:incomes){total += income.getTax();}return total;}}class Income{protected double income;public Income(double income){this.income = income;}public double getTax(){return income * 0.1;}}// 计算税收class Salary extends Income{public Salary(double income){super(income);}@Overridepublic double getTax() {if (income <= 5000){return 0;}return (income - 5000) * 0.2;}}// 国家补贴免税收class StateCouncilSpecialAllowance extends Salary{public StateCouncilSpecialAllowance(double income){super(income);}@Overridepublic double getTax(){return 0;}}
抽象类
- 抽象类只能被继承,目的是让代码更规范,因为子类必须实现父类定义的方法,即覆写父类方法。
- 抽象方法,如果一个类中包含抽象方法,不能包含方法体。那么该类必须是抽象类。任何子类必须重写父类抽象方法,除非子类也是抽象类。
package com.pan3a.abstractStudy;public class AbstractStudy {public static void main(String[] args) {Person personOne = new Student("pan3a",18);personOne.run();System.out.println(personOne.getName());}}abstract class Person{private String name;private int age;public Person(){}public Person(String name,int age){this.name = name;this.age = age;}public abstract void run();public String getName(){return name;}}class Student extends Person{private String name;private int age;public Student(){}// 此处不能使用Override来检查,因为构造房啊不会被继承public Student(String name,int age){super(name,age);}@Overridepublic void run(){System.out.println("Student run");}public void say(){System.out.println("Hello " + this.name);}@Overridepublic String getName(){String name = super.getName();return name;}}
接口
- 接口也可继承,可一个类实现多个接口
- 接口可以定义
default
方法。
- 接口默认的方法都是
public abstract
,这两个只是被省略了。
package com.pan3a.interfaceStudy;public class ObjectInterface {public static void main(String[] args) {Student personOne = new Student("Pan3a");personOne.say();personOne.red();personOne.medium();personOne.printColor();System.out.println(personOne.getName());}}interface Person{void say();String getName();}interface Color{void red();// 定义接口方法,可以直接被继承调用default void printColor(){System.out.println("this is interface default method");}}// 接口继承接口interface Size extends Color{void medium();}// 一个类实现多个接口class Student implements Person,Color,Size{private String name;public Student(String name){this.name = name;}@Overridepublic void say(){System.out.println("Hello World!");}@Overridepublic String getName(){return this.name;}@Overridepublic void red(){System.out.println("this is hello method!");}@Overridepublic void medium() {System.out.println("this is medium!");}}
内部类
- 一:直接创建一个类定义在另一个类的内部
- 这里的访问必须实例化外部类再来请求,内部类可访问父类的私有属性。
package com.pan3a.Inner;public class ObjectInner {public static void main(String[] args) {Person personOne = new Person("Pan3a");Person.Student student = personOne.new Student();student.info();}}class Person{private String name;public Person(String name){this.name = name;}class Student{void info(){System.out.println("Hello " + Person.this.name + " I am a Student!");}}}
- 二:匿名类,不需要在内部定义一个类,直接实例化。
public class ObjectInnerAnonymous {public static void main(String[] args) {AnonymousDemo anonymousDemo = new AnonymousDemo("Pan3a");}}class Inner{public void display(){System.out.println("在 Inner 类内部。");}}class AnonymousDemo{private String name;public AnonymousDemo(String name){this.name = name;inner.display();}// 匿名类继承一个类Inner inner = new Inner(){@Overridepublic void display(){System.out.println("在匿名类内部。");}};}
- 静态内部类
枚举
- 枚举限制变量只能使用预先设定好的值,相当于常量。如四季的春夏秋冬。
- 通过
name()
获取常量定义的字符串,注意不要使用
toString()
,因为它可以被覆盖。
-
ordinal()
获取常量定义的顺序,类似于数组的顺序,但是并没有实质意义,因为更改枚举元素之后顺序会发生变化。
-
enum
的构造方法要声明为
private
,字段强烈建议声明为
final
,常用于
switch
语句中。
-
enum
中也可以编写构造方法,字段,方法。
- 常量普通设定方法
class Year{public static final String spring = "spring";public static final String summer = "summer";public static final String autumn = "autumn";public static final String winter = "winter";}
- 注意Java版本在
JDK8
版本之前使用
equals
进行输入对比判断。也可也使用
===
进行判断。如果使用
==
比较,它比较的是两个引用类型的变量是否是同一个对象。因此,引用类型比较,要始终使用
equals()
方法,但
enum
类型可以例外。
class Year{public static final String spring = "spring";public static final String summer = "summer";public static final String autumn = "autumn";public static final String winter = "winter";}public class EnumStudy {public static void main(String[] args) {String day;Scanner scan = new Scanner(System.in);day = scan.nextLine();scan.close();if(day.equals(Year.spring) || day.equals(Year.autumn)){System.out.println("OK");}}}
- 迭代枚举元素
enum Years{SPRING,SUMMER,AUTUMN,WINTER;}public class EnumStudy {public static void main(String[] args) {for (Years y: Years.values()){System.out.println(y);}}}
- 结合
switch
反射
-
Java
的反射,Java的反射是指程序在运行期可以拿到一个对象的所有信息。
- 创建一个类,后面用来进行测试使用,注意请将一下测试文件都放在一个包内。
package com.pan3a.reflection;public class ReflectionMain {}class Person{private int age;private String name;public long id=9527;public long grade;protected float score;protected int rank;public Person(){}protected Person(long id){this(18,"Pan3a",id,9,9999,31);}private Person(int age){this(age,"Pan3a",9527,9,9999,30);}public Person(int age,String name,long id,long grade,float score,int rank){this.age = age;this.name = name;this.id = id;this.grade = grade;this.score = score;this.rank = rank;}public int getAge(){return age;}public void setAge(int age){this.age = age;}public String getName(){return name;}public void setName(String name){this.name = name;}public long getId(){return id;}public void setId(long id){this.id = id;}public long getGrade(){return grade;}public void setGrade(long grade){this.grade = grade;}public float getScore(){return score;}public void setScore(float score){this.score = score;}public int getRank(){return rank;}public void setRank(int rank){this.rank = rank;}private static void sayHello(){System.out.println("Hello World");}private void sayHello(String name){System.out.println("Hello " + name);}@Overridepublic String toString(){final StringBuffer stringBuffer = new StringBuffer("Person{");stringBuffer.append("age=").append(age);stringBuffer.append(", name=\'").append(name).append(\'\\\'\');stringBuffer.append(", id=").append(id);stringBuffer.append(", grade=").append(grade);stringBuffer.append(", score=").append(score);stringBuffer.append(", rank=").append(rank);stringBuffer.append(\'}\');return stringBuffer.toString();}}class Teacher extends Person{private String role = "Teacher";public void sayHello(){System.out.println("Hello Teacher");}}class Student extends Teacher{private String role = "Student";@Overridepublic void sayHello(){System.out.println("Hello Student");}}
获取对象
- 对象的获取有三种方式分别是
Class.forName(全类名)
,
对象.getclass()
,
类名.class
。
- 这里的三种方式虽然作用都一样,但是都有各自的缺点。
-
class.forName
需要知道类名的全路径。
对象名.class
需要存在已经实例化的对象。
类名.class
需要提前在编译前知道类名。
- 下面会发现这里的比较都是
true
,因此说这里返回的对象都是同一个,因此
Person.class
只加载了一次。
- 用
instanceof
不但匹配指定类型,还匹配指定类型的子类。而用
==
判断
class
实例可以精确地判断数据类型,但不能作子类型比较。
package com.pan3a.reflection;public class ReflectionGetClass {public static void main(String[] args) throws Exception{com.pan3a.reflection.Student student = new com.pan3a.reflection.Student();com.pan3a.reflection.Teacher teacher = new com.pan3a.reflection.Teacher();com.pan3a.reflection.Person person = new com.pan3a.reflection.Person();if(student instanceof com.pan3a.reflection.Person){System.out.println("Student 是 Person 子类");}// Class.forNameClass class1 = Class.forName("com.pan3a.reflection.Person");System.out.println("别名:" + class1.getSimpleName());System.out.println(class1);// 类名.classClass class2 = com.pan3a.reflection.Person.class;System.out.println(class2);// 对象.getClass()com.pan3a.reflection.Person person1 = new com.pan3a.reflection.Person();Class class3 = person1.getClass();System.out.println(class3);System.out.println(class1 == class2);System.out.println(class1 == class3);}}
成员变量
- 获取成员变量需要知道一下四个方法,
getField
,
getFields
,
getDeclaredField
,
getDeclaredFields
。
- 还可获取成员变量属性的三个方法,
getType
,
getModifiers
,
getName
。分别是获取变量类型,修饰符,成员名。
- 他们分别是获取单个成员,和获取所有成员,获取单个成员(忽略修饰服限制,不包括父类),获取多个成员(忽略修饰服限制,不包括父类)。需注意的是使用后面两个是需使用
setAccessible(true)
来忽略编译时的安全检查。
- 这里牵扯到了反射实现构造方法,后面也再会讲到。
package com.pan3a.reflection;import java.lang.reflect.Field;import java.lang.reflect.Modifier;public class ReflectionGetField {public static void main(String[] args) throws Exception{Class class1 = Class.forName("com.pan3a.reflection.Person");getFieldStudy(class1);getFieldsStudy(class1);getDeclaredFieldStudy(class1);getDeclaredFieldsStudy(class1);setFieldStudy(class1);}public static void getFieldStudy(Class class1) throws Exception{System.out.println("getField");Field fieldId = class1.getField("id");System.out.println(fieldId);Field fieldGrade = class1.getField("grade");System.out.println(fieldGrade);System.out.println();// 该对象还有其他成员但是用此方法无法获取,因为他们不是用public修饰的}public static void getFieldsStudy(Class class1){System.out.println("getFields");Field[] fields = class1.getFields();for (Field field : fields){System.out.println(field);}System.out.println();}public static void getDeclaredFieldStudy(Class class1) throws Exception{System.out.println("getDeclaredField");Field fieldAge = class1.getDeclaredField("age");System.out.println(fieldAge);Field fieldName = class1.getDeclaredField("score");System.out.println(fieldName);System.out.println();}public static void getDeclaredFieldsStudy(Class class1) throws Exception{System.out.println("getDeclaredFields");Field[] fields = class1.getDeclaredFields();for(Field field:fields){System.out.println("成员名:" + field.getName() + "\\t成员修饰符:" + field.getModifiers() + "\\t成员类型:" + field.getType());}System.out.println();}// 反射修改私有成员值public static void setFieldStudy(Class class1) throws Exception{System.out.println("反射获取,修改成员值");com.pan3a.reflection.Person person = new com.pan3a.reflection.Person();System.out.println("ID:" + person.getId());// 反射获取成员变量值并且修改成员变量Field fieldAge = class1.getDeclaredField("id");fieldAge.setAccessible(true);// 实例化对象为后面获取,修改成员做准备,这里后面还会讲到的构造方法Object object = class1.newInstance();System.out.println("ID:" + fieldAge.get(object));fieldAge.set(object,9999);System.out.println("ID:" + fieldAge.get(object));}}
构造方法
- 平常正向操作都是
new
一个对象。通过反射调用构造方法有两种方式,分别是
Person.class.newInstance()
,
(Person)constructor.newInstance()
。两者区别就是前者无法调用含参的构造方法,后者可以。
- 实例化对象时,对于非
public
的任然需要
constructor.setAccessible(true)
。
package com.pan3a.reflection;import java.lang.reflect.Constructor;public class ReflectionConstructor {public static void main(String[] args) throws Exception{Class personClass = Class.forName("com.pan3a.reflection.Person");System.out.println("所有构造方法");Constructor[] constructors = personClass.getDeclaredConstructors();for (Constructor constructor:constructors){System.out.println(constructor);}System.out.println();System.out.println("public无参数构造方法");// 默认当前类的无参数构造方法Constructor constructor1 = personClass.getConstructor();System.out.println(constructor1);System.out.println("protected带参数构造方法");Constructor constructor2 = personClass.getDeclaredConstructor(long.class);System.out.println(constructor2);System.out.println("private带参数构造方法");Constructor constructor3 = personClass.getDeclaredConstructor(int.class);System.out.println(constructor3 + "\\n");System.out.println("public无参数构造方法创建对象");Object person1 = constructor1.newInstance();System.out.println(person1);System.out.println("protected带参数构造方法创建对象");constructor2.setAccessible(true);Object person2 = constructor2.newInstance(9528);System.out.println(person2);System.out.println("private带参数构造方法创建对象");constructor3.setAccessible(true);Object person3 = constructor3.newInstance(18);System.out.println(person3);System.out.println("Person.class.newInstance()");Class class1 = com.pan3a.reflection.Person.class;Object object = class1.newInstance();System.out.println(object);}}
成员方法
- 获取成员方法如通获取成员变量类似,也有四个方法。
getMethod
,
getMethods
,
getDeclaredMethod
,
getDeclaredMethods
。
- 获取方法属性,
getName
,
getReturnType
,
getParameterTypes
,
getModifiers
。
package com.pan3a.reflection;import java.lang.reflect.Method;public class ReflectionMethod {public static void main(String[] args) throws Exception{Class personClass = Class.forName("com.pan3a.reflection.Person");getMethodStudy(personClass);// getMethodsStudy(personClass);getDeclaredMethodStudy(personClass);// getDeclaredMethodsStudy(personClass);}public static void getMethodStudy(Class personClass) throws Exception{System.out.println("getMethod获取单个非public方法");Object object = personClass.newInstance();Method method = personClass.getMethod("getId");System.out.println(method);long Id = (long) method.invoke(object);System.out.println("Id:" + Id);// 多态,依旧根据传入的实例化对象为准,如果没有则向父类寻找Class teacherClass = Class.forName("com.pan3a.reflection.Teacher");Method method1 = teacherClass.getMethod("sayHello");method1.invoke(new com.pan3a.reflection.Student());}public static void getMethodsStudy(Class personClass) throws Exception{System.out.println("getMethods获取所有非public方法");Method[] methods = personClass.getMethods();for (Method method:methods){System.out.println(method);}}public static void getDeclaredMethodStudy(Class personClass) throws Exception{System.out.println("getDeclaredMethod单个方法不限制修饰符");Object object = personClass.newInstance();Method method = personClass.getDeclaredMethod("sayHello",String.class);System.out.println(method);method.setAccessible(true);method.invoke(object,"Pan3a");// 由于这里和方法为静态方法,因此object为nullMethod method1 = personClass.getDeclaredMethod("sayHello");method1.setAccessible(true);method1.invoke(null);}public static void getDeclaredMethodsStudy(Class personClass) throws Exception{System.out.println("获取所有方法");Method[] methods = personClass.getDeclaredMethods();for(Method method:methods){System.out.println("方法名:" + method.getName() + "\\t方法返回值类型:" + method.getReturnType() + "\\t方法参数类型:" + method.getParameterTypes() + "\\t方法修饰符:" + method.getModifiers());}}}
继承关系
-
getSuperclass()
,获取父类类型,
getInterfaces()
获取当前类实现的所有接口。
package com.pan3a.reflection;public class ReflectionSuper {public static void main(String[] args) throws Exception{superClass();interfaceReflection();}public static void superClass() throws Exception{Class studentClass = Class.forName("com.pan3a.reflection.Student");Class teacherClass = studentClass.getSuperclass();Class personClass = teacherClass.getSuperclass();Class objectClass = personClass.getSuperclass();Class objectSuperClass = objectClass.getSuperclass();System.out.println(studentClass);System.out.println(teacherClass);System.out.println(personClass);System.out.println(objectClass);// 综合可看出除了Object类外,如果类没有继承,那么默认继承Object。System.out.println(objectSuperClass);}public static void interfaceReflection() throws Exception{Class integer = Integer.class;Class[] integerInterfaces = integer.getInterfaces();for (Class integerInterface:integerInterfaces){System.out.println(integerInterface);}}}
动态代理
- 平常实现接口方式。
package com.pan3a.reflection;public class ReflectionDynamicProxy {public static void main(String[] args) {HelloWorld helloWorld = new HelloWorld();helloWorld.morning("Pan3a");}}interface Hello{void morning(String name);}class HelloWorld implements Hello{public void morning(String name){System.out.println("Good morning " + name);}}
- 动态代理实现方法
package com.pan3a.reflection;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ReflectionDynamicProxy {public static void main(String[] args) {InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method);if(method.getName().equals("morning")){System.out.println("Good morning," + args[0]);}return null;}};Hello hello = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),new Class[] {Hello.class},invocationHandler);hello.morning("Pan3a");}}interface Hello{void morning(String name);}
泛型
- 泛型就是定义一种模板
使用泛型
- 泛型类型实际上就是
Object
- 使用泛型时就是把
<T>
替换成需要的class类型
package com.pan3a.generics;import java.util.Arrays;public class GenericsInterface {public static void main(String[] args) {Person[] person = new Person[]{new Person("Pan3a",18),new Person("Forever404",20),};Arrays.sort(person);System.out.printf(Arrays.toString(person));}}class Person implements Comparable<Person>{String name;int score;Person(String name, int score){this.name = name;this.score = score;}public int compareTo(Person other){return this.name.compareTo(other.name);}public String toString(){return this.name + "," + this.score;}}
编写泛型
public class GenericsEditor {public static void main(String[] args) {}}// 多泛型 class Pair<T, K>class Pair<T>{private T first;private T last;public Pair(T first, T last){this.first = first;this.last = last;}public T getFirst(){return first;}public T getLast(){return last;}// 静态方法使用泛型public static <K> Pair<K> create(K first, K last){return new Pair<K>(first,last);}}
擦拭法
- 泛型实现方式是擦拭法(Type Erasure)。
- Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型
T
视为
Object
处理,但是,在需要转型的时候,编译器会根据
T
的类型自动为我们实行安全地强制转型。
- 局限一,
<T>
不能是基本类型,例如
int
,因为实际类型是
Object
,
Object
类型无法持有基本类型。必须是如
<Intager>
。
- 局限二,无法取得泛型的
Class。
- 局限三,无法判断带泛型的类型
- 局限四不能实例化
<T>
类型,因为编译器会把
<T>
看成
<Object>
。
package com.pan3a.generics;import java.lang.reflect.Type;import java.lang.reflect.ParameterizedType;public class GenericsErasure {public static void main(String[] args) {Pair<String> pairOne = new Pair<>("Hello","World");Pair<Integer> pairTwo = new Pair<>(123,456);Class classOne = pairOne.getClass();Class classTwo = pairTwo.getClass();System.out.println(classOne == classTwo);System.out.println(classOne == Pair.class);/* 泛型类无法判断其类型比如String,Integerif (pairOne instanceof pairTwo){System.out.println("");}*/// 泛型类继承Class<IntPair> clazz = IntPair.class;Type type = clazz.getGenericSuperclass();if (type instanceof ParameterizedType){ParameterizedType parameterizedType = (ParameterizedType) type;Type[] types = parameterizedType.getActualTypeArguments();// 可能有多个泛型类型Type firstType = types[0]; //获取第一个泛型类Class<?> typeClass = (Class<?>) firstType;System.out.println(typeClass);}}}class Pair<T>{private T first;private T last;public Pair(T first,T last){this.first = first;this.last = last;}public T getFirst(){return first;}public T getLast(){return last;}}class IntPair extends Pair<Integer> {public IntPair(Integer first, Integer last) {super(first, last);}}
extends通配符
-
<? extends Number>
通配符方法。
- 引用通配符方法时,
Number number = Object.getFirst();
这里的
Number
不能为
integer
,这样可能因为读取出来的是
Double
类型导致类型不匹配而报错。
- 使用
extends
时表示可读不可写。
package com.pan3a.generics.extend;public class GenericsExtends {public static void main(String[] args) {Pair<Integer> pair = new Pair<Integer>(123,456);int n = add(pair);System.out.println(n);}// static int add(Pair<Number> p) 这样也会报错无法识别因为Pair<Integer>不是Pair<Number>的子类static int add(Pair<? extends Number> pair){Number first = pair.getFirst();Number last = pair.getLast();// 这里会直接编译错误,因为我们如果传入的是Double setFirst是Integer型 因此会出现类型不匹配// pair.setFirst(new Integer(first.intValue() + 100));return first.intValue() + last.intValue();}}class Pair<T>{private T first;private T last;public Pair(T first, T last){this.first = first;this.last = last;}public T getFirst(){return first;}public T getLast(){return last;}public void setFirst(T first){this.first = first;}public void setLast(T last){this.last = last;}}
super通配符
-
<? super Integer>
通配符方法。
- 可以调用传入
Integer
引用的方法,例如:
obj.setFirst(Integer n);
-
super
通配符表示只能写不能读。
- 无限定通配符
<?>
很少使用,可以用
<T>
替换,同时它是所有
<T>
类型的超类。
package com.pan3a.generics.supers;public class GenericsSuper {public static void main(String[] args) {Pair<Number> pairOne = new Pair<>(12.3, 45.6);Pair<Integer> pairTwo = new Pair<>(123, 456);setSame(pairOne,100);setSame(pairTwo,200);System.out.println(pairOne.getFirst() + " " + pairOne.getLast());System.out.println(pairTwo.getFirst() + " " + pairOne.getLast());}static void setSame(Pair<? super Integer> pair,Integer integer){pair.setFirst(integer);pair.setLast(integer);}}class Pair<T>{private T first;private T last;public Pair(T first, T last){this.first = first;this.last = last;}public T getFirst(){return first;}public T getLast(){return last;}public void setFirst(T first){this.first = first;}public void setLast(T last){this.last = last;}}
无限定通配符
-
<?>
既不能读也不能写。
-
Pair<?>
是
Pair<T>
的超类,因此可以向上转型。
public class main{public static void main(String[] args) {Pair<Integer> p = new Pair<>(123, 456);Pair<?> p2 = p; // 安全地向上转型System.out.println(p2.getFirst() + ", " + p2.getLast());}}class Pair<T> {private T first;private T last;public Pair(T first, T last) {this.first = first;this.last = last;}public T getFirst() {return first;}public T getLast() {return last;}public void setFirst(T first) {this.first = first;}public void setLast(T last) {this.last = last;}}
泛型与反射
集合
List
- List可添加重复元素和null,有ArrayList和LinkedList优先使用前者。
- 遍历时使用
for each
或者
Iterator
,推荐使用前者,操作简单。
import java.util.ArrayList;import java.util.Arrays;import java.util.Iterator;import java.util.List;public class collectionList {public static void main(String[] args) {List<String> list = addList();forList(list);iterationList(list);forEachList(list);String[] array = listToArray(list);arrayToList(array);}static void createList(){// JDK9 这里不接受null// List<Integer> list = List.of(1,2,3);}static List<String> addList(){List<String> list = new ArrayList<>();list.add("apple");list.add("pear");list.add("apple");list.add(null);System.out.println(list.size());String second = list.get(3);System.out.println(second);return list;}static void forList(List<String> list){System.out.println("For循环遍历");for(int count=0; count<list.size(); count++){String string = list.get(count);System.out.println(string);}}static void iterationList(List<String> list){System.out.println("Iteration迭代遍历");for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){String string = iterator.next();System.out.println(string);}}static void forEachList(List<String> list){System.out.println("for each 遍历");for(String string:list){System.out.println(string);}}static String[] listToArray(List<String> list){System.out.println("List转换成Array");String[] array = list.toArray(new String[list.size()]);// 数字的话等价 Number可兼容其他类型 Number[] array = list.toArray(Number[]::new);for (String string:array){System.out.println(string);}return array;}static void arrayToList(String[] array){System.out.println("Array转换成List");// 这里返回的是个只读List 无法add removeList<String> list = Arrays.asList(array);System.out.println(list);}}
编写equals
-
List
的
contains()
判断是否包含某个变量、
indexOf()
获取变量所处序号位置。
- 在
List
中查找元素时,
List
的实现类通过元素的
equals()
方法比较两个元素是否相等,因此,放入的元素必须正确覆写
equals()
方法,Java标准库提供的
String
、
Integer
等已经覆写了
equals()
方法,如果不在
List
中查找元素,就不必覆写
equals()
方法。
- 确定两个实例是否相等首先用
instanceof
判断是否是Object类型,对引用类型用
Objects.equals()
比较,对基本类型直接用
==
比较。
- 如果不调用
List
的
contains()
、
indexOf()
这些方法,那么放入的元素就不需要实现
equals()
方法。
package com.pan3a.collection.equals;import java.util.ArrayList;import java.util.List;import java.util.Objects;public class collectionEquals {public static void main(String[] args) {List<String> stringList = new ArrayList<>();stringList.add("A");stringList.add("B");System.out.println(stringList.contains("A"));System.out.println(stringList.contains("C"));// 因为Java内部String类实现类equals方法不是===对比,因此为trueSystem.out.println(stringList.contains(new String("A")));System.out.println("---------------------");System.out.println(stringList.indexOf("A"));System.out.println(stringList.indexOf("C"));System.out.println(stringList.indexOf(new String("A")));System.out.println("----------------------");List<Person> list = new ArrayList<>();list.add(new Person("Pan3a","Pan3a",18));list.add(new Person("Forever404","Forever404",20));System.out.println(list.contains(new Person("Pan3a","Pan3a",18)));System.out.println(list.indexOf(new Person("Forever404","Forever404",20)));}}class Person{String firstName;String lastName;int age;public Person(String firstName, String lastName, int age){this.firstName = firstName;this.lastName = lastName;this.age = age;}// 因为Person类没有系统自带的equals方法因此需要自己写 而String Integer这些Java标准库已经实现类equals方法public boolean equals(Object object){if(object instanceof Person){Person person = (Person) object;return Objects.equals(this.firstName,person.firstName) && this.age == person.age && Objects.equals(this.lastName,person.lastName);}return false;}}
编写Map
- 类似于字典的key,value对应。
package com.pan3a.collection.map;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class collectionMap {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("apple",123);map.put("pear",456);forEachKey(map);forEachEntrySet(map);testMap();}static void forEachKey(Map<String, Integer> map){for (String key : map.keySet()){Integer value = map.get(key);System.out.println(key + " = " + value);}}static void forEachEntrySet(Map<String, Integer> map){System.out.println("--------EntrySet--------");for (Map.Entry<String, Integer> entry : map.entrySet()){String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + " = " + value);}}static void testMap(){List<Student> list = new ArrayList<>();list.add(new Student("Bob",77));list.add(new Student("Pan3a",89));list.add(new Student("Forever404",79));Students students = new Students(list);System.out.println(students.getScore("Bob") == 77 ? "测试成功" : "测试失败");System.out.println(students.getScore("Tom") == -1 ? "测试成功" : "测试失败");System.out.println(students.findInList("Bob"));}}class Student{String name;int score;Student(String name, int score){this.name = name;this.score = score;}}class Students{List<Student> list;Map<String, Integer> cache;Students(List<Student> list){this.list = list;cache = new HashMap<>();}/** 根据name查找score,找到返回score,未找到返回-1*/int getScore(String name){Integer score = this.cache.get(name);if(score == null){//}return score == null ? -1 : score.intValue();}Integer findInList(String name){for(Student student : this.list){if (student.name.equals(name)){return student.score;}}return null;}}
编写equals和hashCode
-
HashMap
,作为
key
的类必须正确覆写
equals()
和
hashCode()
方法;一个类如果覆写了
equals()
,就必须覆写
hashCode()
,并且覆写规则是:如果
equals()
返回
true
,则
hashCode()
返回值必须相等;
- 如果
equals()
返回
false
,则
hashCode()
返回值尽量不要相等。
实现
hashCode()
方法可以通过
Objects.hashCode()
辅助方法实现。
package com.pan3a.collection.hashcode;import java.util.HashMap;import java.util.Map;import java.util.Objects;public class collectionHashCode {public static void main(String[] args) {String string = new String("Hello");String test = new String("Hello");System.out.println(string.hashCode());System.out.println(test.hashCode());System.out.println(string.equals(test));System.out.println(string == test);System.out.println("-------hashcode && equals------");Person personOne = new Person("Pan3a",18);Map<Person,Integer> map = new HashMap<>();map.put(personOne,123);Person personTwo = new Person("Pan3a",18);System.out.println(personOne == personTwo);System.out.println(personOne.equals(personTwo));System.out.println(map.get(personOne));System.out.println(map.get(personTwo));}}class Person{public String name;public int age;Person(String name, int age){this.name = name;this.age = age;}@Overridepublic int hashCode(){return Objects.hashCode(age) + Objects.hashCode(name);}@Overridepublic boolean equals(Object object){if(object instanceof Person){Person person = (Person) object;return Objects.equals(this.name,person.name) && this.age == person.age;}return false;}}
编写EnumMap
- 如果
Map
的key是
enum
类型,推荐使用
EnumMap
,既保证速度,也不浪费空间。使用
EnumMap
的时候,根据面向抽象编程的原则,应持有
Map
接口。
import java.time.DayOfWeek;import java.util.EnumMap;import java.util.Map;public class collectionEnumMap {public static void main(String[] args) {Map<DayOfWeek,String> map = new EnumMap<>(DayOfWeek.class);map.put(DayOfWeek.MONDAY,"星期一");map.put(DayOfWeek.TUESDAY,"星期二");map.put(DayOfWeek.WEDNESDAY,"星期三");map.put(DayOfWeek.TUESDAY,"星期四");map.put(DayOfWeek.FRIDAY,"星期五");map.put(DayOfWeek.SATURDAY,"星期六");map.put(DayOfWeek.SUNDAY,"星期日");System.out.println(map);System.out.println(map.get(DayOfWeek.MONDAY));}}
使用TreeMap
-
SortedMap
在遍历时严格按照Key的顺序遍历,最常用的实现类是
TreeMap
;作为
SortedMap
的Key必须实现
Comparable
接口,或者传入
Comparator
;要严格按照
compare()
规范实现比较逻辑,否则,
TreeMap
将不能正常工作。
package com.pan3a.coolestions.treemap;import java.util.Comparator;import java.util.Map;import java.util.TreeMap;public class collectionTreeMap {public static void main(String[] args) {sortingMap();}public static void test(){Map<String,Integer> map = new TreeMap<>();map.put("orange",1);map.put("apple",2);map.put("pear",3);for(String key: map.keySet()){System.out.println(key);}}public static void sortingMap(){Map<Person,Integer> map = new TreeMap<>(new Comparator<Person>() {@Overridepublic int compare(Person personOne, Person personTwo) {if(personOne.score == personTwo.score){return 0;}return personOne.score > personTwo.score ? -1 : 1;}});map.put(new Person("Pan3a",78),1);map.put(new Person("Forever404",89),2);map.put(new Person("Bob",62),3);for (Person key : map.keySet()){System.out.println(key);}System.out.println(map.get(new Person("Bob",62)));}}class Person{public String name;public int score;Person(String name, int score){this.name = name;this.score = score;}@Overridepublic String toString(){return String.format("{%s: score=%d}",name,score);}}
使用Properties
- Java集合库提供的
Properties
用于读写配置文件
.properties
。
.properties
文件可以使用UTF-8编码。可以从文件系统、classpath或其他任何地方读取
.properties
文件。读写
Properties
时,注意仅使用
getProperty()
和
setProperty()
方法,不要调用继承而来的
get()
和
put()
等方法。
import java.io.*;import java.util.Properties;public class collectionProperties {public static void main(String[] args){testRead();bytesCodeRead();testWrite();}public static void testRead(){// 为啥相对路径不行String filePath = "/Users/pan3a/CodeProject/JavaProject/src/setting.properties";Properties properties = new Properties();try {properties.load(new FileInputStream(filePath));} catch (IOException exception) {exception.printStackTrace();System.out.println(exception);}String getFilePath = properties.getProperty("last_open_file");// 设置默认值120 当不存在该配置时String getInterval = properties.getProperty("auto_sava_interval","120");System.out.println(getFilePath);System.out.println(getInterval);}public static void bytesCodeRead() {String settings = "# test" + "\\n" + "course=Java" + "\\n" + "last_open_date=2019-08-07T12:35:01";ByteArrayInputStream input = null;try {input = new ByteArrayInputStream(settings.getBytes("UTF-8"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}Properties props = new Properties();try {props.load(input);} catch (IOException e) {e.printStackTrace();}System.out.println("course: " + props.getProperty("course"));System.out.println("last_open_date: " + props.getProperty("last_open_date"));System.out.println("last_open_file: " + props.getProperty("last_open_file"));System.out.println("auto_save: " + props.getProperty("auto_save", "60"));}public static void testWrite() {Properties properties = new Properties();properties.setProperty("url","https://www.baidu.com");properties.setProperty("language","Java");try {properties.store(new FileOutputStream("/Users/pan3a/CodeProject/JavaProject/src/setting.properties"),"这是写入的注释");} catch (IOException e) {e.printStackTrace();}}}
使用Set
-
Set
用于存储不重复的元素集合:放入
HashSet
的元素与作为
HashMap
的key要求相同;放入
TreeSet
的元素与作为
TreeMap
的Key要求相同;利用
Set
可以去除重复元素;遍历
SortedSet
按照元素的排序顺序遍历,也可以自定义排序算法。
import java.util.*;public class collectionSet {public static void main(String[] args) {testSet();treeSet();}static void testSet(){Set<String> set = new HashSet<>();System.out.println(set.add("Pan3a"));System.out.println(set.add("Forever404"));System.out.println(set.add("Pan3a"));System.out.println(set.contains("Pan3a"));System.out.println(set.remove("Panda"));System.out.println(set.size());}static void treeSet(){System.out.println("--------------------------");List<Message> messageList = new ArrayList<>();messageList.add(new Message(1,"Hello!"));messageList.add(new Message(2,"发工资了吗"));messageList.add(new Message(2,"发工资了吗"));messageList.add(new Message(3,"中午吃啥子"));messageList.add(new Message(3,"中午吃啥子"));List<Message> displayMessages = process(messageList);// 避免重复展示数据for (Message message : displayMessages){System.out.println(message.text);}}static List<Message> process(List<Message> received){Set<Message> messageSet = new TreeSet<>();List<Message> messageListTwo = new ArrayList<>();for(Message message : received){messageSet.add(message);}for (Message message : messageSet){messageListTwo.add(message);}return messageListTwo;// return received;}}class Message implements Comparable<Message>{public final int sequence;public final String text;Message(int sequence, String text) {this.sequence = sequence;this.text = text;}@Overridepublic int compareTo(Message message) {if (this.sequence == message.sequence){return 0;}return this.sequence > message.sequence ? 1 : -1;}}
使用Queue
- 队列
Queue
实现了一个先进先出(FIFO)的数据结构:通过
add()
/
offer()
方法将元素添加到队尾;通过
remove()
/
poll()
从队首获取元素并删除;通过
element()
/
peek()
从队首获取元素但不删除。要避免把
null
添加到队列。
import java.util.LinkedList;import java.util.Queue;public class collectionQueue {public static void main(String[] args) {Queue<String> queue = new LinkedList<>();queue.offer("apple");queue.offer("pear");queue.offer("banana");System.out.println(queue.poll());System.out.println(queue.element());System.out.println(queue.element());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());}}
使用PriorityQueue
-
PriorityQueue
实现了一个优先队列:从队首获取元素时,总是获取优先级最高的元素。
PriorityQueue
默认按元素比较的顺序排序(必须实现
Comparable
接口),也可以通过
Comparator
自定义排序算法(元素就不必实现
Comparable
接口)。
import java.util.Comparator;import java.util.PriorityQueue;import java.util.Queue;public class collectionPriorityQueue {public static void main(String[] args) {testPriorityQueue();testUserPriorityQueue();}public static void testPriorityQueue(){Queue<String> queue = new PriorityQueue<>();queue.offer("apple");queue.offer("pear");queue.offer("banana");System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());}public static void testUserPriorityQueue(){System.out.println("--------------------");Queue<User> queue = new PriorityQueue<>(new UserComparator());queue.offer(new User("Bob","A7"));queue.offer(new User("Alice","A2"));queue.offer(new User("Pan3a","V10"));queue.offer(new User("Jack","A3"));queue.offer(new User("Hack","V2"));int counts = queue.size();for(int count = 0; count < counts; count++) {System.out.println(queue.poll());}}}class User{public final String name;public final String number;public User(String name, String number){this.name = name;this.number = number;}@Overridepublic String toString(){return name + "/" + number;}}class UserComparator implements Comparator<User> {@Overridepublic int compare(User userOne, User userTwo) {if(userOne.number.charAt(0) == userTwo.number.charAt(0)){return userOne.number.compareTo(userTwo.number);}if (userOne.number.startsWith("V")){return -1;}else {return 1;}}}
使用Deque
-
Deque
实现了一个双端队列(Double Ended Queue),它可以:将元素添加到队尾或队首:
addLast()
/
offerLast()
/
addFirst()
/
offerFirst()
;
- 从队首/队尾获取元素并删除:
removeFirst()
/
pollFirst()
/
removeLast()
/
pollLast()
;
- 从队首/队尾获取元素但不删除:
getFirst()
/
peekFirst()
/
getLast()
/
peekLast()
;
- 总是调用
xxxFirst()
/
xxxLast()
以便与
Queue
的方法区分开;
- 避免把
null
添加到队列。
import java.util.Deque;import java.util.LinkedList;public class collectionDeque {public static void main(String[] args) {Deque<String> deque = new LinkedList<>();deque.offerLast("A");deque.offerLast("B");deque.offerFirst("C"); // C <= A <= BSystem.out.println(deque.pollFirst());System.out.println(deque.pollLast());System.out.println(deque.pollFirst());}}
使用Stack
- 栈(Stack)是一种后进先出(LIFO)的数据结构,操作栈的元素的方法有:把元素压栈:
push(E)
;
- 把栈顶的元素“弹出”:
pop(E)
;
- 取栈顶元素但不弹出:
peek(E)
。
在Java中,我们用
Deque
可以实现
Stack
的功能,注意只调用
push()
/
pop()
/
peek()
方法,避免调用
Deque
的其他方法。最后,不要使用遗留类
Stack
。
使用Iterator
-
Iterator
是一种抽象的数据访问模型。使用
Iterator
模式进行迭代的好处有:对任何集合都采用同一种访问模型;
- 调用者对集合内部结构一无所知;
- 集合类返回的
Iterator
对象知道如何迭代。
Java提供了标准的迭代器模型,即集合类实现
java.util.Iterable
接口,返回
java.util.Iterator
实例
import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class collectionIterator {public static void main(String[] args) {ReverseList<String> reverseList = new ReverseList<>();reverseList.add("Apple");reverseList.add("Orange");reverseList.add("Pear");for (String string : reverseList){System.out.println(string);}}}class ReverseList<T> implements Iterable<T>{private List<T> list = new ArrayList<>();public void add(T t){list.add(t);}public Iterator<T> iterator(){return new ReverseIterator(list.size());}class ReverseIterator implements Iterator<T>{int index;ReverseIterator(int index){this.index = index;}@Overridepublic boolean hasNext() {return index > 0;}@Overridepublic T next() {index--;return ReverseList.this.list.get(index);}}}
使用Collections
-
Collections
类提供了一组工具方法来方便使用集合类:创建空集合;
- 创建单元素集合;
- 创建不可变集合;
- 排序/洗牌等操作。
import java.util.ArrayList;import java.util.Collections;import java.util.List;public class collectionCollections {public static void main(String[] args) {testCollections();mutableCollections();}public static void testCollections(){List<String> list = new ArrayList<>();list.add("apple");list.add("pear");list.add("orange");System.out.println(list);// 排序Collections.sort(list);System.out.println(list);// 随机顺序Collections.shuffle(list);System.out.println(list);}public static void mutableCollections(){System.out.println("---------------------");List<String> mutable = new ArrayList<>();mutable.add("apple");mutable.add("pear");List<String> immutable = Collections.unmodifiableList(mutable);mutable.add("orange");System.out.println(immutable);}}