JavaStudy
2021-10-15 14:49
197 查看
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() { // 重载方法,过滤不需要的文件 @Override public 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(); // 如果代码出错,并不会回收输入流,可用try readFile(); // 一次读取一个字节不高效,因此可以使用缓冲 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!"); }else System.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{ @Override public 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{ @Override public 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); } @Override public double getTax() { if (income <= 5000){ return 0; } return (income - 5000) * 0.2; } } // 国家补贴免税收 class StateCouncilSpecialAllowance extends Salary{ public StateCouncilSpecialAllowance(double income){ super(income); } @Override public 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); } @Override public void run(){ System.out.println("Student run"); } public void say(){ System.out.println("Hello " + this.name); } @Override public 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; } @Override public void say(){ System.out.println("Hello World!"); } @Override public String getName(){ return this.name; } @Override public void red(){ System.out.println("this is hello method!"); } @Override public 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(){ @Override public 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); } @Override public 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"; @Override public 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.forName Class class1 = Class.forName("com.pan3a.reflection.Person"); System.out.println("别名:" + class1.getSimpleName()); System.out.println(class1); // 类名.class Class 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为null Method 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() { @Override public 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,Integer if (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 remove List<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方法不是===对比,因此为true System.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; } @Override public int hashCode(){ return Objects.hashCode(age) + Objects.hashCode(name); } @Override public 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>() { @Override public 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; } @Override public 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; } @Override public 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; } @Override public String toString(){ return name + "/" + number; } } class UserComparator implements Comparator<User> { @Override public 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 <= B System.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; } @Override public boolean hasNext() { return index > 0; } @Override public 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); } }
相关文章推荐
- Digdata Development Java__Study_05(String,回顾)
- studyNote_java基础_Day23
- 判断java类型 -- study20180419
- studyNote_java基础_Day11
- java study 08day--多态中成员的特点
- studyNote_java基础_Day12
- Thinking in Java Study(08)
- JAVA.Study.Note.JAVA入门之值类型与引用类型
- java_study_path
- Digdata Development Java__Study_13(Java中线程Thread,线程池ExecutorService)
- studyNote_java基础_day03
- Java Study@2014-10-02
- java –url for study
- java study 02day--位运算符
- java study 06day--单例设计模式
- Java Study Day1
- java study IO//FILE pipe
- [学习笔记]Thinking in Java (the 2nd edition) Study Note (1)
- Java Study 03
- 【Java Web StudyNote】JSP implicit objects