Note of Java Learning Java 语法基础 引用 Java中有引用 的概念,类似于C语言的指针。
例如改变指向数组指针(引用数组) 的值:
数组也好,字符串通过地址引用也好,都与指针如出一辙嘛。
for each 1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { int [] ns = { 1 , 4 , 9 , 16 , 25 }; for (**int n : ns**) { System.out.println(n); } } }
int n定义变量,“**:**”用于遍历数组。
此时n直接拿到数组的元素,无需索引,若用ns[i]这种形式存在索引。
输入输出 1 2 3 4 5 6 7 8 9 10 11 12 Scanner scanner = new Scanner (System.in);System.out.print("Input your name: " ); String name = scanner.nextLine();System.out.print("Input your age: " ); int age = scanner.nextInt();System.out.printf("Hi, %s, you are %d\n" , name, age);
Java面向对象 一个.java源文件可以定义多个类,但只能有一个public class 且类名需要与文件名相同
类内有field和method,若定义private field,则不能从类外直接操作field值,但可以调用类内的public方法来间接操作field,在类内方法可以加赋值的限制条件 ,以此来解耦合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.hit.demo;public class Hello { public static void main (String[] args) { Person gf = new Person (); gf.name = "AzusaSeren" ; gf.age = 27 ; System.out.println(gf.name); System.out.println(gf.age); gf.setScore(95.5 ); gf.setWeight(44.5 ); double weight = gf.getWeight(); double score = gf.getScore(95 ,62 ); System.out.println(weight+"\n" +score); } static class Person { public String name; public int age; private double score; private double weight; public void setScore (double score) { this .score = score; } public double getScore (double bestScore, double lastScore) { calcScore(bestScore,lastScore); return this .score; } private void calcScore (double bestScore, double lastScore) { this .score = bestScore - lastScore; } public void setWeight (double weight) { this .weight = weight; } public double getWeight () { return this .weight; } } }
Person gf = new Person();
为定义一个引用类型为Person的变量gf指向一个Person类的实例 。
private method不能从外部调用,只能在类内调用。
这说明方法可以封装一个类的对外接口 ,调用方不需要知道也不关心Person
实例在内部到底有没有score。
this关键字 1 2 3 4 5 6 7 class Person { private String name; public void setName (String name) { this .name = name; } }
this.name是类的field,第二个name是方法的局部变量。
可变参数 1 2 3 4 5 6 7 class Group { private String[] names; public void setNames (String... names) { this .names = names; } }
调用方法赋值时:
1 2 3 Group.setNames("Azusa" ,"Seren" ); Group.setNames("hck" ); Group.setNames();
以上均可,另外java在给字符串数组赋值时需要new一个字符串对象 :
1 2 3 String[] names = new String [] {"hck" , "azusa" }; Group.setNames(new String [] {"hck" , "azusa" });
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void class main (){ City test = new City ("Beijing" ,500 ); System.out.println(test.getName()); System.out.println(test.getAge()); } class City { private String name; private int age; **public City (String name, int age) **{ this .name = name; this .age = age; } public String getName () { return this .name; } public int getage () { return this .age; } }
如上,类似于PHP的魔术函数__construct__(),构造函数可在对象调用时直接传参赋值 。
若在类内已经赋值:
1 2 3 4 5 6 7 class Perosn { private String sex = "male" ; public String Person (String sex) { this .sex = sex; return sex; } }
但在调用时又赋值,以后赋值为准。
注:构造方法无法返回值,只需用public修饰符即可。
方法重载 方法名相同,但功能不同的一组方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person { private String name; private int age; private int sex; public void person (String name) { this .name = name; } public void person (int age) { this .age = age; } public void person (int sex) { this .sex = sex; } }
调用时:
1 2 3 4 5 6 public static void class main (){ Person p = new Person (); p.person("Azusa" ); p.perosn(15 ); p.person(2 ); }
继承 可用extends关键字继承父类的属性和方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 static class Person { protected String name; private int age; public void person (String name) { this .name = name; } public void person (int age) { this .age = age; } public int getAge () { return this .age; } public String getName () { return this .name; } } **static class Student extends Person **{ static int SCORE_BEST = 100 ; private double score; public String hello () { return "hello" + name; } public void setScore (double score) { if (score > 0 && score <= SCORE_BEST) { this .score = score; } else { this .score = 0 ; } } public double getScore () { return score; } }
但注意:实例化子类后,新实例会自动继承所有父类的属性和方法,但无法访问父类实例化复制后的private属性 ,只能访问public和protected。
例如上例实例化后:
1 2 3 4 public static void class main (String[] arags){ Person p = new Person (15 ); Student stu = new Student (); }
在子类内无法访问父类的age属性,也就得不到15的赋值。
protected
关键字可以把字段和方法的访问权限控制在继承树内部,一个protected
字段和方法可以被其子类,以及子类的子类所访问。
若从子类访问父类属性,且已经有同名变量,可用super关键字:
1 2 3 4 5 6 7 8 9 10 public Student extends Person { private int stuAge; public void setStuAge (int age) { this .stuAge = age; } public String getAge () { return "Your father's age is " + **super **.age; return "Your age is " + this .stuAge; } }
由于子类不会继承 任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。
super关键字还可用于调用父类构造方法:
1 2 3 4 5 6 7 8 class Student extends Person { protected int score; public Student (String name, int age, int score) { super (name, age); this .score = score; } }
多态与覆写 子类中存在与父类的方法名完全相同的方法,而且此方法返回值也相同,称之为覆写。
1 2 3 4 5 6 7 8 9 10 11 12 class Person { public void run () { System.out.println("Person.run" ); } } class Student extends Person { @Override public void run () { System.out.println("Student.run" ); } }
那如果调用子类时,究竟执行哪一个?
例如
1 2 Person p = new Student ();p.run();
实际运行时执行的不是引用标识的Person,而是Student,即调用时的实例是动态的,这种面向对象的特性称之为“多态”。
多态的意义是复用代码,大大提高程序的可扩展性 。
子类调用父类中被覆写过的方法 1 2 3 4 5 6 7 8 9 10 11 class Person { protected String name; public String hello () { return "Hello " + name; } } class Student extends Perosn { public String hello () { return super .hello() + " !" ; } }
final修饰符 可阻止子类继承父类的方法,或阻止子类继承父类
1 2 3 4 5 6 7 final class Person { protected String name; } Student extends Person { }
抽象类 面向抽象编程 只有规范没有具体实现的类称为抽象类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { public static void main (String[] args) { Person p = new Student (); p.run(); } } **abstract ** class Person { public abstract void run () ; } class Student extends Person { @Override public void run () { System.out.println("Student.run" ); } }
Person类的run方法无具体实现,需要在子类内对该方法进行覆写
1 2 3 4 5 6 7 8 public class Main () { public static void main (String[] args) { Perosn p1 = new Student (); Person p2 = new Teacher (); **p1.run(); p2.run();** } }
这样在调用run()方法时不用关心实际方法来自哪个子类的覆写。
面向抽象编程 的本质就是:
上层代码只定义规范(例如:abstract class Person
);
不需要子类就可以实现业务逻辑(正常编译);
具体的业务逻辑由不同的子类实现,调用者并不关心。
接口 当一个抽象类没有属性,只有抽象方法时,称之为接口 。
1 2 3 4 interface class Person{ Sting setName (String name) ; void run () ; }
接口中所有方法都是默认“abstract public”的。
default关键字 若接口需新增方法但非所有子类都需要,可用default关键字修饰新方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Main { public static void main (String[] args) { Person p = new Student ("hck" ); p.run(); } } interface Person { String getName () ; **default void run () **{ System.out.println("hello " + getName()); } } class Student implements Person { private String name; public Student (String name) { this .name = name; } public String getName () { return name; } }
Static关键字 静态属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Main (String[] args){ public static void main () { Person p1 = new Person (1111 ); Person p2 = new Person (2222 ); int a1 = p1.age = 1111 ; int a2 = p2.age = 2222 ; **Person.score = 95.5 ; Person.score = 99.5 ; System.out.println(a1 + "\n" + a2); System.out.println(Person.score); } } class Person { public int age; public static double score; public Person (int age) { this .age = age; } }
age属于Person类,实例化后会有一个独立的内存空间存放。而静态属性score为共享内存空间,不能通过实例来操作,只能通过类来操作(类似于作用域不同):
一般属性指向实例,静态属性指向类。
注:interface即接口不能有实例属性,但可以有静态属性:
1 2 3 4 5 6 public interface Person { int MALE = 1 ; int FEMALE = 2 ; }
静态方法 调用实例方法必须通过一个实例变量,例如
1 2 3 Person p = new Person ();p.run();
而调用静态方法则不需要实例变量 ,通过类名就可以调用。静态方法类似其它编程语言的函数 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main { public static void main (String[] args) { Person.setNumber(99 ); System.out.println(Person.number); } } class Person { public static int number; public static void setNumber (int value) { number = value; } }
作用域 java支持边用边定义,使用局部变量时,应该尽可能把局部变量的作用域缩小,尽可能延后声明局部变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package abc;public class Hello { void hi (String name) { String s = name.toLowerCase(); int len = s.length(); if (len < 10 ) { int p = 10 - len; for (int i=0 ; i<10 ; i++) { System.out.println(); } } } }
例如变量 i只在循环内有作用域。
Java内建的访问权限包括public
、protected
、private
和package
权限;
Java在方法内部定义的变量是局部变量,局部变量的作用域从变量声明开始,到一个块结束;
final
修饰符不是访问权限,它可以修饰class
、field
和method
;
一个.java
文件只能包含一个public
类,但可以包含多个非public
类。
异常处理 异常是一种class
,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main (String[] args) { byte [] bs = toGBK("中文" ); System.out.println(Arrays.toString(bs)); } static byte [] toGBK(String s) { try { return s.getBytes("GBK" ); } catch (UnsupportedEncodingException e) { System.out.println(e); return s.getBytes(); } } }
以上用到了getBytes()方法,必须捕获UnsupportedEncodingException才能过编译。
getBytes定义:
1 2 3 public byte [] getBytes(String charsetName) throws UnsupportedEncodingException { ... }
这是因为在该方法定义的时候,使用throws Xxx
表示该方法可能抛出的异常类型。调用方在调用的时候,必须强制捕获这些异常 ,否则编译器会报错。
在toGBK()
方法中,因为调用了String.getBytes(String)
方法,就必须捕获UnsupportedEncodingException
。
在测试时若为方便,可抛出所有异常:
1 2 3 public static void main (String[] args) throws Excpetions{..... }
抛出异常 异常被抛出时,会一直向上层传递,直到被catch。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { public static void main (String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } } static void process1 () { process2(); } static void process2 () { Integer.parseInt(null ); } }
运行上面这段代码返回
显示调用栈,可见异常为一层一层向上传播至main被捕获的。
断言(Assert) 1 2 3 4 5 6 7 Public class main (){ public static void main (String[] arags) { double x = Math.abc(-123.45 ); assert x >= 0 : "X must > 0." ; System.out.println(x); } }
判断x是否大于0,若否则退出程序报错抛出AssertionError:X must > 0.
需要在命令行加参数运行才能使用断言,直接运行JVM会把该行忽略:
注:
在命令行运行java需要先用
1 2 javac com\hit\demo\Main.java
再用java包名+类名的格式运行该文件即可,必须在src文件运行且加包名,否则会报错。
具体参见:Java命令行运行错误: 找不到或无法加载主类
对于可恢复的异常不能用断言,不可恢复的异常多用单元测试,实际很少用断言。
String对象 比较字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class StringTest1 { public static void main (String[] args) { String okName = "1111" ; String passWord = "12345678" ; Scanner scanner = new Scanner (System.in); String name = scanner.next(); String psd = scanner.next(); if (name == okName && psd == passWord){ System.out.println("You're right!" ); }else { System.out.println("NO!" ); } } }
上述代码无法完整功能,因为用双引号定义的字符串存储在字符串常量池 ,而用scanner接受new出来的字符串存储在堆内存 ,因此二者即便内容相同,其地址 不同无法用==比较字符串变量(存储字符串地址),而该用String对象的equals方法:
1 2 3 4 5 if (**name.equals(okName) && psd.equals(passWord**)){ System.out.println("You're right!" ); }else { System.out.println("NO!" ); }
类修饰符 private修饰符修饰的变量属于类实例化出来的对象,不属于类,因此不能直接通过类名 访问。即为实例成员变量。
static修饰符变量为静态成员变量(与实例成员变量相对),属于类,在定义的时候就已加载在内存中,可共享访问——以直接通过实例访问,也可以通过类名访问,同一个类内可以直接用变量名访问。
静态方法:与对象属性无关的通用功能方法 ,方便同一个类中直接访问,无需实例化对象。不能方法实例属性,不能出现this关键字。
实例方法:需要访问对象的属性,非通用方法。
注:静态方法多用于工具类中,工具类的构造方法多用private修饰来阉割。
静态代码块与实例代码块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class StaticCode { public static String Schoolname; public static ArrayList<String> cards = new ArrayList <>(); static { System.out.println("----静态代码块执行" ); Schoolname = "aiheima" ; } StaticCode(){ System.out.println("构造器被触发" ); } { System.out.println("实例代码块被触发" ); public static void main (String[] args) { StaticCode s1 = new StaticCode (); } }
单例设计模式 通过单例类拿对象,只加载一次:
1 2 3 4 5 6 public class singleInstance { public static singleInstance instance = new singleInstance (); private singleInstance () { } }
如上为饿汉单例,在创建类的同时加载类。
拿对象时:
1 2 3 4 5 public class Test1 { public static void main (String[] args) { singleInstance s1 = singleInstance.instance; } }
懒汉单例:在需要对象的时候才创建单例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class lanHan { private static lanHan instance; public static lanHan getInstance () { if (instance == null ){ instance = new lanHan (); } return instance; } private lanHan () {} }
1 2 3 4 5 6 7 8 9 public class Test1 { public static void main (String[] args) { lanHan s1 = lanHan.getInstance(); lanHan s2 = lanHan.getInstance(); System.out.println(s1); System.out.println(s2); } }
继承 子类可以继承父类私有成员,但无法访问。
子类只能继承一个父类。
可用super关键字访问父类方法和有参数构造器。
1 2 3 4 5 6 7 8 9 public class Teach extends Person { public Teach () { } public Teach (String name, int age) { super (name,age); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Person { private String name; private int age; public Person () {} public Person (String name,int age) { this .name = name; this .age = age; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } }
this() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Students { private String name; private int age; public Students () {} **public Students (String name) { this (name,111111 ); }** public Students (String name,int age) { this .age = age; this .name = name; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } }
1 2 3 4 5 6 7 8 public class Test1 { public static void main (String[] args) { Students s1 = new Students ("张三" ,111 ); System.out.println(s1.getName()); Students s2 = new Students ("李四" ); System.out.println(s2.getAge()); } }
this()用于在类内调用兄弟构造器。
注:this()与super()在构造器中都只能在第一行(故不能共存于构造器中) ,即优先初始化父类构造器或者兄弟构造器。
方法重写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class ReWrite { public static void main (String[] args) { NewPhone hw = new NewPhone (); hw.call(); hw.sendMsg(); } } class NewPhone extends Phone { @Override public void call () { super .call(); System.out.println("开始视频" ); } @Override public void sendMsg () { super .sendMsg(); System.out.println("发送图片" ); } } class Phone { public void call () { System.out.println("打电话" ); } public void sendMsg () { System.out.println("发信息" ); } public static void test () { } }
方法重写只用于子类中重写父类的方法,来增加子类的功功能。
Protected修饰符 只能被同一包内类或者不同包的子类 访问。
final修饰符
修饰类:不能产生子类
修饰方法:不能重写
修饰变量:有且仅有一次赋值(约等于const)
注:修饰引用变量时,地址值不变,但地址指向的对象内容可改变
常量 public static final修饰的变量,必须有初始化值,且执行中其值不能改变。
常量在编译阶段会进行宏替换,方便维护。
枚举 用于信息分类和标志的数据类型
枚举的优势:可读性好,入参约束严谨(相比常量)
抽象类 抽象方法只能声明,不能写方法体 。
抽象类是不完整的设计图,通常用作父类来给子类继承(抽象类作为标准约束子类,只能复写)。
1 2 3 public abstract class Animal { public abstract void run () ; }
继承抽象类的子类必须重写所有抽象类的抽象方法 。
类的成员(构造器,属性,方法)在抽象类中都有。
抽象类可没有抽象方法,但抽象方法一定需要在抽象类中。
抽象类不能创建对象。
抽象类中的非抽象方法可用于做模板方法, 多用final修饰:
接口(Interface) 接口中所有方法都是public abstract,可省略。
接口不能继承,需要用实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class PingPongMan implements SportsMan { private String name; public PingPongMan (String name) { this .name = name; } @Override public void run () { System.out.println("跑步" ); } @Override public void competition () { System.out.println("比赛" ); } }
1 2 3 4 5 6 package com.advanced.d8;public interface SportsMan { void run () ; void competition () ; }
接口与接口:1. 接口支持多实现,即public class main implements Law, Others{}
public interface SportsMan implements Law{}
多态 同类型对象,执行同一方法,出现不同行为 结果称之为多态 。
1 2 3 4 5 6 7 8 9 10 public class Test { public static void main (String[] args) { Animal d = new Dog (); d.run(); Animal b = new Bird (); b.run(); } }
1 2 3 4 5 6 7 8 9 10 public class Test { public static void main (String[] args) { Animal d = new Dog (); System.out.println(d.name); Animal b = new Bird (); System.out.println(d.name); } }
劣势:多态下无法调用子类独有的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Test { public static void main (String[] args) { Animal d = new Dog (); d.run(); Bird b = new Bird (); b.run(); Bird b2 = b; b2.layEgg(); go(new Dog ()); go(new Bird ()); } public static void go (Animal a) { a.run(); if (a instanceof Bird){ Bird b = (Bird) a; b.layEgg(); }else { Dog d = (Dog) a; d.lookDorr(); } } }
如上,可用强制类型转换来解决不能访问子类独有功能的问题。
内部类 内部类即定义再类里面的类:
1 2 3 4 public class People { public class Heart { } }
内部类可以方便地访问外部类private变量
静态内部类 1 2 3 4 5 6 7 8 9 10 11 public class InnerClass { public static int a = 10 ; public static class Iner { private String name; private int age; public static String shoolName; public void show () { System.out.println("名称" + name); System.out.println(a); }
静态内部类可直接访问外部静态变量。
不能直接访问外部类实例成员,要访问需要先new一个外部类对象
用的很少
成员内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class Outer { public static String names = "111" ; public class Inner { private String name; private int age; public Inner () { } public static void show () { System.out.println("name" + names); } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public Inner (String name, int age) { this .name = name; this .age = age; } } }
1 2 3 4 5 6 7 8 9 10 public class Test1 { public static void main (String[] args) { **Outer.Inner i = new Outer ().new Inner (); i.setAge(10 ); i.setName("张三" ); Outer.Inner.show(); } }
成员内部类可直接访问外部类实例成员 变量。
访问外部类对象成员用Outer.this.heartBeat
较静态内部类用的更多
匿名内部类(重要) 一种没有名字的局部内部类,定义在方法中和代码块(例如static{ })中。
作用:方便创建子类对象,无需定义子类即可调用 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.advanced.d10;public class Main { public static void main (String[] args) { **Animal a = new Animal () { @Override public void run () { System.out.println("跑的块" ); } };** a.run(); } } abstract class Animal { public abstract void run () ; }
匿名内部是自身的对象,非父类抽象类或接口的对象(抽象类不能实例化成对象)
匿名内部类对象相当于new之前的类的子类对象。
对象回调:匿名内部类实例化的对象可直接作为参数传入方法。
匿名内部类可实现简化代码。
常用API object toString()默认打印地址,多在子类中重写方法打印对象内容。
equals()比较对象地址,也可在子类中重写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @override public boolean equals (Object o) { if (o instanceof Student){ Student s2 = (Student) o; if (this .name.equals(s2.name)){ return true ; }else { return false } }else { return false ; } }
1 2 3 4 5 6 if (this .name.equals(s2.name)){ return true ; }else { return false } return this .name.equals(s2.name);
StringBuilder类 操作字符串较String性能更好,而且可修改。
因为String对象不可变,只能在拼接字符串时每次都创建新字符串,而StringBuilder只需要在堆内存内操作一个对象即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Test5 { public static void main (String[] args) { StringBuilder sb = new StringBuilder (); sb.append("aaaaaaaa" ); sb.append("1111" ); System.out.println(sb); StringBuilder s1 = new StringBuilder (); **s1.append("a" ).append("bbbb" ).append("2222" ); System.out.println(s1); } }
sb.append()方法可在完成后再返回字符串对象,因此支持链式编程。
注:StringBuider只能操作拼接字符串的手段,最后还是要转成String类型
1 2 3 StringBuilder sb = new StringBuilder ();sb.append("aaaaaaaa" ); String s = sb.toString();
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class TestStringBuilder { public static void main (String[] args) { int [] arr = {111 ,888 ,89 ,979 ,49 ,4 ,94 ,94 ,9 ,49 }; System.out.println(toString(arr)); } public static String toString (int [] arr) { if (arr != null ){ StringBuilder sb = new StringBuilder ("[" ); for (int i = 0 ; i < arr.length; i++) { sb.append(arr[i] ).append(i == arr.length - 1 ? "" : "," ); } sb.append("]" ); return sb.toString(); }else { return null ; } } }
Math类 1 2 3 4 5 6 7 8 9 10 11 12 public class MathTest { public static void main (String[] args) { System.out.println(Math.abs(10 )); System.out.println(Math.floor(1.2 )); System.out.println(Math.pow(2 ,3 )); System.out.println(Math.random()); System.out.println(Math.round(4.49 )); System.out.println(Math.round(4.5 )); } }
System类
BigDecimal类 1 2 double b = 10.0 ;BigDecimal b1 = BigDecimal.valueOf(b);
不能直接new对象和构造器,需要用valueOf方法转 。
注:只能用于精确运算,除不尽时需要用a.divide(b1, 2, RoundingMode.HELP_UP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class DateDemo1 { public static void main (String[] args) { Date d = new Date (); System.out.println(d); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss EEE a" ); String rs = sdf.format(d); System.out.println(rs); } }
时间计算:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class Test1 { public static void main (String[] args) throws ParseException { String dateStr = "2021年08月06日 11:11:11" ; SimpleDateFormat sdf = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss" ); Date d = sdf.parse(dateStr); long time = d.getTime() + (2L *24 *60 *60 + 14 *60 *60 + 49 *60 + 6 ) * 1000 ; System.out.println(sdf.format(time)); } }
包装类 基本数据类型的引用类型
1 2 3 4 5 6 7 8 9 10 11 12 public class BaoZhuanglei { public static void main (String[] args) { int a = 10 ; Integer a1 = 10 ; Integer a2 = a; int a3 = a1; double db = 11.9 ; Double d2 = db; double d3 = d2; } }
容错率高,兼容null:
1 2 3 Integer age = null ;Integer a = 10 ;
最有用的做法:可把字符串类型数值转换为真实的数据类型 :
1 2 3 4 5 6 7 8 String str = "213" ;int age = Integer.parseInt(str);System.out.println(age); String str2 = "99.5" ;double d = Double.parseDouble(str2);System.out.println(d);
正则表达式 多用于数据校验:String类的matches 方法可匹配正则表达式
1 2 3 4 5 6 7 8 9 10 public class RegexDmoe { public static void main (String[] args) { System.out.println(checkqq("15591991" )); } public static Boolean checkqq (String qq) { return qq != null && qq.matches("\\d{6,20}" ); } }
提取信息:
1 2 3 4 5 6 7 8 9 10 11 public class RegexDemo2 { public static void main (String[] args) { String name = "张三daddawda李四dwadawdawwad" ; String[] names = name.split("\\w+" ); for (int i = 0 ; i < names.length; i++) { System.out.println(names[i]); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class RegexDemo2 { public static void main (String[] args) { String name = "张三daddawda李四dwadawdawwadhouchangkun@gmail.com49494949449949dwa9aaddwa49aw4d94" ; String regex = "(\\w{1,30}@[a-zA-z\\d]){2,20}((\\.[a-zA-Z0-9])" + "{2,20}){1,2}|(1[3-9]\\d{9})|(0[1-9]{2,6}--?\\d{5,20})|(400-?\\d{3,9}-?\\d{3,9})|\\W+" ; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(name); while (matcher.find()){ String r1 = matcher.group(); System.out.println(r1); } } }
Arrays类
Arrays.toString(arr)打印数组内容
Arrays.sort(arr)排序数组(默认升序排序)
Arrays.binarySearch(arr, 22)二分查找返回搜索数据的位置,只能用于排好序的数组(查找不到则返回-1)
Lambda表达式 作用:简化匿名内部类的代码写法
1 2 3 (匿名内部类被重写方法的形参列表)->{ 方法体; }
注意:匿名内部类只能简化函数式接口(接口中必须只有一个抽象方法) 的匿名内部类。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Main { public static void main (String[] args) { **Swimming s = () -> { System.out.println("老师游泳" ); };** go(s); System.out.println("-----------" ); go(() ->{ System.out.println("--老师游泳--" ); }); go(() -> System.out.println("--老师游泳--" )); } public static void go (Swimming s) { s.swim(); } } @FunctionalInterface interface Swimming { void swim () ; }
Lambda也可继续简化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.LambdaTest;import java.util.Arrays;import java.util.Comparator;public class Demo { public static void main (String[] args) { Integer[] arr = {12 ,59 ,4 ,49 ,49 ,9 }; Arrays.sort(arr, new Comparator <Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); System.out.println(Arrays.toString(arr)); Arrays.sort(arr, (Integer o1, Integer o2) -> { return o2 - o1; }); System.out.println(Arrays.toString(arr)); **Arrays.sort(arr, ((o1, o2) -> o2 - o1));** System.out.println(Arrays.toString(arr)); } }
集合
多用于数据个数不能确定 ,且需要进行增删 元素。
集合只能存储引用类型数据
体系结构:
List系列集合:添加的元素是有序,可重复,有索引
Set系列集合:无序,不重复,无索引
集合支持泛型,用于约束集合所存储的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CollectionTest { public static void main (String[] args) { Collection<String> list = new ArrayList <>(); list.add("java" ); list.add("java" ); System.out.println(list); Collection list1 = new HashSet (); list1.add("java" ); list1.add(111 ); list1.add("java" ); list1.add(true ); System.out.println(list1); } }
**c.addall(c1)**可将c1中所有元素导入c中。
迭代器遍历集合元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CollectionTest { public static void main (String[] args) { Collection<String> list = new ArrayList <>(); list.add("java" ); list.add("MYsql" ); list.add("python" ); list.add("C++" ); System.out.println(list); **Iterator<String> it = list.iterator();** while (it.hasNext()){ String ele = it.next(); System.out.println(ele); }
可用增强for简化迭代器: 1 2 3 for (String s : list) { System.out.println(s); }
Lambda表达式 1 2 3 4 5 6 7 8 9 10 list.forEach(new Consumer <String>() { @Override public void accept (String s) { System.out.println(s); } }); list.forEach(s -> System.out.println(s)); list.forEach(System.out::println);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Main2 { public static void main (String[] args) { Collection<Movie> movies = new ArrayList <>(); movies.add(new Movie ("111" ,9.5 ,"ddd3423" )); movies.add(new Movie ("111w322" ,8.5 ,"ddd324324" )); movies.add(new Movie ("111324324" ,1.5 ,"dd324342d" )); for (Movie movie : movies) { System.out.println(movie.getActor()); System.out.println(movie.getName()); System.out.println(movie.getScore()); } } }
List系列集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com;import java.util.ArrayList;import java.util.List;public class ListTest { public static void main (String[] args) { List<String> list = new ArrayList <>(); list.add("Java" ); list.add("java" ); list.add("Java" ); list.add(2 ,"HTML" ); System.out.println(list); System.out.println(list.remove(2 )); System.out.println(list); list.set(2 ,"c++" ); System.out.println(list); System.out.println(list.get(2 )); } }
ArrayList 底层基于数组,增删较慢,索引定位较快。
LinkedList底层基于双链表,首尾操作较快,查询较慢
LinkedList实现栈和对列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class LinkListTest { public static void main (String[] args) { LinkedList<String> stack = new LinkedList <>(); stack.push("111" ); stack.addFirst("2222" ); stack.addFirst("33333333" ); stack.addFirst("444444444" ); System.out.println(stack.pop()); System.out.println(stack.removeFirst()); System.out.println(stack.removeFirst()); System.out.println(stack.removeFirst()); System.out.println(stack); LinkedList<String> queue = new LinkedList <>(); queue.addLast("1" ); queue.addLast("22" ); queue.addLast("33" ); queue.addLast("444" ); System.out.println(queue); queue.removeLast(); queue.removeLast(); queue.removeLast(); System.out.println(queue); } }
边遍历边删除问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class ListTest { public static void main (String[] args) { List<String> list = new ArrayList <>(); list.add("Java" ); list.add("java" ); list.add("Java" ); list.add(2 ,"HTML" ); System.out.println(list); Iterator<String> it = list.listIterator(); while (it.hasNext()){ String ele = it.next(); if ("Java" .equals(ele)){ **it.remove(); } } }
用集合 删除元素后i++导致跳过一个元素,应用迭代器 删除元素。
自定义泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.ListTest1;import java.util.ArrayList;public class MyArrayList <E> { ArrayList<String> list = new ArrayList <>(); public void add (E s) { list.add(s); } public void remove (E s) { list.remove(s); } }
泛型方法 定义方法的同时定义了泛型的方法,就是泛型方法。
1 public <T> void show (T t) {}
可接受数据类型更灵活。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Test { public static void main (String[] args) { String[] names = {"hhh" , "duwagwd" , "dwidwadwa" }; Integer[] ages = {121 ,324 ,2434 ,455 }; printArray(ages); printArray(names); } **public static <T> void printArray (T[] t) { StringBuilder sb = new StringBuilder ("[" ); for (int i = 0 ; i < t.length; i++) { sb.append(t[i]).append(i != t.length - 1 ? "," : "" ); } sb.append("]" ); System.out.println(sb); }** }
对于String和Integer均可接受,但注意只能为引用类型。
泛型接口
通配符 用于使用泛型时:
1 2 public static void go (ArrayList<?> cars) {}
Set系列集合 特定:无序,不重复,无索引
HashSet 底层基于哈希表和红黑树。
Collection集合总结:
可变参数 接受数据非常灵活,收参数可以为不确定个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.D1;import java.lang.reflect.Array;import java.util.Arrays;public class MethodDemo { public static void main (String[] args) { sum(); sum(1000 ); sum(10 ,25 ,59 ,19 ,19 ); sum(new int []{15 ,59 ,9 ,29 ,19 ,9 }); } public static void sum (int ...nums) { System.out.println(Arrays.toString(nums)); } }
注:可变参数只能放在形参列表的最后.
Collection工具类 1 2 3 4 5 6 7 8 9 10 public class CollectionsDemo { public static void main (String[] args) { List<String> list = new ArrayList <>(); Collections.addAll(list,"wdaihidowa" ,"fuyghj" ,"fuygihjlk" ); Collections.shuffle(list); System.out.println(list); } }
sort() method:
1 2 3 4 5 6 ArrayList<Integer> lists = new ArrayList <>(); Collections.addAll(lists,116 ,94 ,4 ,94 ,94 ,94 ,94 ,4 ,9 ,151 ,51 ,51 ); Collections.sort(lists); System.out.println(lists);
比较器
Map集合(键值对集合) 键:有序 不重复 无索引
Maps遍历
获取所有键的集合:Set keySet()
1 2 3 4 5 6 7 Maps<String, Integer> maps = new HashMap <>(); Set<String> set = maps.keySet(); for (String key : set) { int value = maps.get(key); System.out.println(key + "=>" + value); }
先把Maps集合转为Set集合
1 2 3 4 5 6 7 Set<Map.Entry<String, Integer>> entries = maps.entrySet(); for (Map.Entry<String, Integer> entry : entries) { String key = entry.getKey(); int value = entry.getValue(); System.out.println(key + "=>" + value); }
Lambda表达式
1 2 3 4 5 6 7 8 9 maps.forEach(new BiConsumer <String, Integer>() { @Override public void accept (String s, Integer integer) { System.out.println(s + "=>" + integer); } }); **maps.forEach((s, integer) -> System.out.println(s + "=>" + integer));**
其他实现类 LinkedHashMap:有序,无索引,不重复
TreeMap:键可排序,无索引,无重复