JavaStudy
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);
}
}
逆水行舟,不进则退。