Java基础
程序运行
终端javac
编译成.class,使用java
运行,javadoc
生成注释文档
基本数据类型
float
和double
为近似值byte
,short
,int
三者在计算时会转换为int
类型,可以使用强制类型转换
short s1 = 10;
int s2 = s1+1;//必须加int,因为类型变了
s1 = (short)(s1+1);//强制类型转换
s1 +=1;//没问题
键盘输入
要先引入Scanner
类才能使用键盘输入
import java.util.Scanner
运算符
&
,|
即可以表示逻辑运算符,也可以表示按位运算符;表示逻辑运算符时针对boolean变量,先计算两边的值再做比较
按位运算符计算乘除结果比普通乘除快(是最快的方式):>>
除以2的n次方;<<
乘以2的n次方
两个变量交换的三种方法
int a=10,b=12;
//第一种方法
int c=a;
a=b;
b=c;
//第二种方法
a = a+b-(b=a);
//第三种方法
a = a+b;
b = a-b;
a = a-b;
//第四种方法
a = a*b;
b = a/b;
a = a/b;
//第五种方法(最快)不能是相同值
a = a^b;
b = a^b;
a = a^b;
方法重载
在一个类中可以有多个同名的方法,参数和定义不同,但返回值必须一样,将根据参数类型自动匹配相应的方法
数组
java定义数组的方式
//第一种
int[] nums1 = new int[5];
//第二种
int[] nums2;
nums = new int[5];
//第三种
int[] nums3 = new int[]{1,2,3,4,5};
//第四种
int[] nums4 = {1,2,3,4,5};
x.length
表示数组的长度
foreach遍历数组:每次读取数组的一个值并赋值给num
for(int num:nums1){}
可变参数:只能定义在参数列表的最后一个,表示参数个数可变,作为数组使用
public stasic void fun(
int... 变量名
){}
数组存储:数组是引用类型,栈内存存储地址,指向堆内存的值
Array类常用方法
- **Arrays.binarySearch(int[] array,int value);**:二分查找
- Arrays.toString(int[] array);:将数组转换成字符串打印
- Arrays.sort(int[] array);:数组排序
- Arrays.copyOf(int[] array,int length); Arrays.copyOf(int[] array,int from,int to); **System.arraycopy(Object src,int srcPos,Object dest,int destPos,int length)**(原数组,原数组起始位置,目标数组,目标数组起始位置,复制长度) 数组复制
- Arrays.equels();:判断两个数组是否相等,不能用==,
==比较的是地址
- Arrays.fill();:填充数组
内存机制
栈内存:大小固定,用于存储局部,临时变量(基本数据类型)和引用变量(存储地址)
堆内存:大小不固定,存储对象
面向对象
存储机制
变量存储在栈内存中,当为空类时堆内存不存内容,栈内存的变量无地址;
当给变量实例化后,栈内存中存储地址指向堆内存的值;
当堆中内存没有任何一个栈内存指向它时,会被JVM的GC程序认为是垃圾而回收
public class Horse{
String name;//引用变量,在堆内存中存储的是指向具体值的地址
int age;
public void(){
System.out.priintln("我是"+name+"今年"+age+"岁了");
}
Horse horse1 = null;//空类,栈内存无地址指向堆内存
Horse horse2 = new Horse();//实例化,栈内存存储地址指向堆内存的name和age
horse2.name = "小黑";
horse2.age = "500";
//对象赋值
Horse horse3 = null;
horse3 = horse2;//相同类的对象之间才可以赋值,此时栈内存中变量horse2,horse3指向同一块堆内存地址
horse3.name = "小白";//此时horse2.name跟着改变,因为两者存储地址一致
Horse horse4 = new Horse();
horse4.name = "小红";
horse4 = horse2;//“小红”被当为垃圾
horse2 = null;//释放对象
}
封装
类中的方法存储在方法区,调用时进入栈内存,调用完之后回到方法区
成员变量有默认值,成员变量使用前必须先赋值
在方法中使用变量,使用就 近原则
构造方法
构造方法在new对象的时候自动最先执行
方法名称与类名相同,没有返回值声明
class Dog{
public Dog(){
//内容为空时为默认的构造方法
System.out.println("构造方法");
}
//构造方法的重载
public Dog(String name,int age){
this.name = name;
this.age = age;
System.out.println("方法重载");
}
//构造方法的相互调用
public Dog(String name,int age,int sex){
this(name,age);//调用其他构造方法,只能放在第一句
this.sex = 1;
}
String name;
int age;
int sex;
}
Dog dog1 = new Dog();
Dog dog2 = new Dog("旺旺",5);
private Dog(){}
:私有构造方法,私有化后该类不能new新对象
this关键字
哪个对象使用this,this就表示该类
类名.this.xxx:调用某个指定类中的方法,变量
值传递和引用传递
字符串String相当于一个对象,当调用改变时,字符串变量指向新的堆内存,而不是改变地址上的值,但类中的String型变量指向堆内存的地址上存储的是值的地址,当调用方法改变时,会改变堆内存中值的地址的值,所以变量的值会改变
public class RefDemo{
public static void main(String[] args){
int a = 1;
String name = "小飞";
method1(a,name);
Duck d = new Duck();
method2(d);
System.out.println("a = "+a);//a=1
System.out.println("name = "+name);//name=小飞
System.out.println("d.age = "+d.age);//d.age=5
System.out.println("d.name = "+d.name);//d.name=大黄鸭
}
public static void method1(int sa,String sname){
sa = 2;
sname = "小备";
}
public static void method2(Duck duck){
duck.age = 5;
duck.name = "大黄鸭";
}
}
class Duck{
int age = 2;
String name = "小黄鸭";
}
对象的一对一关系
class Hero{
private String name;
private int age;
private Weapen weapen;//一对一(双向)
public void setWeapen(Weapen weapen){
this.weapen = weapen;
}
public Weapen getWeapen(){
return weapen;
}
public Hero(){}
public Hero(String name,int age){
this.name = name;
this.age = age;
}
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;
}
}
public Weapen{
private String name;
private int grade;
private Hero hero;//一对一关系,双向
public void setHero(Hero hero){
this.hero = hero;
}
public Hero getHero(){
return hero;
}
public Weapen(){}
public Weapen(String name,int grade){
this.name = name;
this.grade = grade;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setGrade(int grade){
this.grade = grade;
}
public int getGrade(){
return grade;
}
}
static关键字
- 定义的变量、方法不属于对象,而依赖于类
- 定义的变量时全局变量,生命周期从类被加载一直到程序结束
- 存储机制:定义的变量、方法只有一份,存储在静态方法区中,该类的所有对象共享这一份内容
- 使用时最好直接使用类名调用,避免混淆
- 静态方法不能访问非静态属性方法,只能访问静态属性和方法
- 当使用某一个对象改变其修饰的变量的值时,所有的对象中的值都被改变
main函数
参数:String[] args 字符串数组,可以传参,传参方式:在终端java 类名 参数
代码块
- 普通代码块,在方法中写的代码块,用于限制生命周期
- 构造代码块,比构造方法先执行
- 静态代码块,最先执行,且多次new对象时只执行一次(第一次使用类时执行),用于项目中初始化只调用一次的数据
public class Test{
public static void main(String[] args){
{
//普通代码块,限制生命周期
int i = 2;
}
//此处无法使用i
}
}
class Student{
static{
//静态代码块,最先执行,并且只在第一次生成对象时执行
}
{
//构造代码块,比构造方法先执行,每生成一个新对象都执行一次
}
public Student(){}
}
对象数组
即数组中的每个值都是一个对象
继承
关键字extends
继承只能继承非私有的(private)
构造方法不能被继承,创建子类时,父类的构造方法会被调用,用于初始化数据super关键字
- 子类中用于表示调用父类的属性
- 用于调用父类的方法,特别是子类的方法被重写后,调用父类原来的方法(
super.方法名
) - 实例化子类对象时,会先调用父类的构造方法,如果父类中没有默认的构造方法,那么子类必须显示的通过
super(...)
来调用父类的构造方法,super只能用于子类构造方法的第一句
class Test{
public static void main(String[] args){
HomeDog homeDog = new HomeDog("旺财");
homeDog.print();
}
}
class Dog{
protected String name;
private int age;
public Dog(String name,int age){
this.name = name;
this.age = age;
System.out.println("Dog的构造方法");
}
}
class HomeDog extends Dog{
public HomeDog(String name){
super(name,2);//只能放在第一句,用于调用父类的构造方法
System.out.println("HomeDog的构造方法");
}
public print(){
System.out.println(super.name);//与下面相同,此处super表示父类
System.out.println(name);
}
}
方法重写
- 发生在子类中,方法重写的两个方法返回值,方法名,参数列表必须完全一致
- 子类方法抛出的异常不能超过父类抛出的异常
- 子类方法的访问级别不能低于父类相应方法的访问级别
- private,static,final修饰的的方法不能被重写
final关键字
final表示最终的,即不可以再改变的
- 修饰的变量相当于常量,其值不能改变(通常定义一个常量类)
- 定义的方法只能被继承不能被重写
- 定义的类不能被继承
- 形参使用final修饰,传入的实参不能被更改
抽象类
1.使用关键字abstract
定义抽象类和抽象方法,抽象方法没有实现
2.继承抽象类的具体类,必须实现所有抽象方法,抽象类继承抽象类则不需要
3.抽象类不能被实例化,不能用final修饰
4.抽象类可以有实现方法和属性、构造方法
abstract class People{
public abstract void name();//抽象方法,只有声明,没有实现
}
接口
- 使用
interface
关键字 - 接口中只能定义常量,抽象方法,JDK1.8以后可以有默认实现方法,也可以有静态方法
public default 返回值 function(){实现内容}
- 接口可以继承多个接口(extends xxx,xxx)
- 具体类实现接口使用
implements
,一个类可以实现多个接口 - 抽象类实现接口可以不实现接口里的方法
- 接口里的方法没有访问权限修饰符时默认是public
- 接口不能有构造方法
- 接口不能被实例化
interface IEat{
void eat();//相当于public abstract void eat()
int NUM = 10;//10,相当于public static final int fianl NUM = 10
public default void print(){
System.out.println("eat");
}
}
interface ISleep extends IEat{
//继承
void sleep();
}
class Girl implements ISleep{
//要实现所有方法
}
多态
- 方法重载和重写
- 用父类的引用指向子类对象
- 当需要把父类强制转换为子类型引用时,为了防止报类型转换错误,
java.lang.ClassCastException
,先用关键字instanceof
进行类型检查,用于判断对象是否是指定的类型(对象本身及父类以上都通过),是就返回true,否则返回falsea instanceof className
public class Test7{
public static void main(String[] args) {
Chicken yc = new YeChicken("小鸡");//用父类的引用指向子类对象(大类型表示小类型),自动向上转型
Chicken hc = new HomeChicken("大鸡");
Chicken wc = new WuChicken("乌鸡");
yc.eat();
hc.eat();
yc = hc;//不会报错
eat(yc);//若没有instanceof判断,会报类型转换错误,两个子类无法强制转换
eat(wc);
}
//具体调用谁的eat看参数对象属于哪个类
//面向抽象编程
public static void eat(Chicken c){
c.eat();
if(c instanceof WuChicken){
WuChicken wc = (WuChicken)c;//强制类型转换(向下转型)
wc.song();
}
}
}
abstract class Chicken{
protected String name;
public Chicken(){};
public Chicken(String name){
this.name = name;
}
public abstract void eat();
}
class YeChicken extends Chicken{
public YeChicken(String name){
super(name);
}
public void eat(){
System.out.print(name+"吃饭");
}
}
class HomeChicken extends Chicken{
public HomeChicken(String name){
super(name);
}
public void eat(){
System.out.print(name+"吃饭");
}
}
class WuChicken extends Chicken{
public WuChicken(String name){
super(name);
}
public void eat(){
System.out.print(name+"吃饭");
}
public void song(){
System.out.print(name+"炖乌鸡");
}
}
Object类
每个类都使用Object作为超类,所有对象(包括数组)都实现这个方法
所有类都是Object类的子类
常用方法:
- public String toString():返回该对象名称的字符串表示,建议重写
- public boolean equals(Object obj):比较两个对象的地址是否相等,根据情况可以重写
- protected void finalize() throws Throwable:垃圾回收
- public final Class<?>getClass():返回此Object的运行时类
内部类
在一个类的内部定义的类
class Outer{
class Inner{}
}
编译时会产生两个文件
Outer.class和Outer$Inner.class
- 成员内部类:直接定义在类中
/*对内部类的访问*/
//需要通过外部类对象才能实例化内部类对象,因为类的非静态属性必须依赖于对象
//通常不建议这样做
Outer outer = new Outer();
Outer.Inner inner = outer.new.Inner();
//在外部类中定义一个方法,对外提供访问接口
class Outer{
private String name;
public void innerPrint(){
Inner inner = new Inner();
inner.print();
}
//一般把内部类设置为私有权限
private class Inner{
public void print(){
System.out.println("inner");
}
}
}
//外部调用:
outer.innerPrint();
- 方法内部类:在一个方法中定义的类
- 方法内部类只能在该方法中被实例化,不能被外部实例
- 方法内部类对象只能使用该内部类所在方法的常量
//该方法在上面的类中
public void show(){
(final) int x=10;
class Inner2{
public void print(){
//x++; //不能改变变量的值,只能用
System.out.println(x);
}
}
Inner2 inner2 = new Inner2();
inner2.print();
}
- 静态内部类:在一个类内部定义一个静态内部类:
- 静态内部类仅能访问外部类的静态成员和方法
//外部调用
Outer.Inner3 inner3 = new Outer.Inner3();
inner3.print();
class Outer{
private String name="Outer";
static class Inner3{
public void print(){
System.out.println("静态内部类");
}
}
}
- 匿名内部类:没有名字的内部类
- 不能有构造方法,只能有一个实例(一次性)
- 不能有任何静态成员、方法
- 没有权限操作符
- 属于局部内部类
优先考虑静态内部类(无依赖),不会产生内存泄漏
//继承式匿名内部类
public void print1(){
//虽然是实例化抽象类,但在实例化的同时实现内部抽象方法
Cat cat = new Cat(){
public void eat(){
System.out.prinln("继承式匿名内部类");
};//注意分号,本质上还是一条语句
}
cat.eat();
}
abstract class Cat(){
public abstract void eat();
}
//接口式匿名内部类
public void print2(){
Eat eat = new Eat(){
public void eat(){
System.out.println("接口式匿名内部类");
}
};
eat.eat();
}
interface Eat(){
public void eat();
}
//参数式匿名内部类
//main方法中
Outer outer = new Outer;
outer.print3(new Eat(){
public void eat(){
System.out.println("参数式匿名内部类");
}
});
class Outer{
public void print3(Eat eat){
eat.eat();
}
}
基本数据类型包装类
java对八种基本数据类型都进行了包装类
八种包装类分为两大类型:
Number:Integer、Short、Long、Double、Float、Byte是其子类
Object:Character、Boolean都是其子类
装箱及拆箱操作:
- 将一个基本数据类型转换为包装类,称为装箱
- 将一个包装类转换成基本数据类型,称为拆箱
Integer i1 = new Integer(10);//自动装箱
Integer i2 = 10;//与上面语句一样
int i3 = il.intValue();//自动拆箱
Interger i4 = new Integer("123");//自动将数值字符串转换成数值对象(只能是数值字符串)
int i5 = Integer.parseInt("123");//将数值字符串转换成数值
Integer i6 = Integer.valueOf("123");//将数值字符串转换成Integer对象实例
享元模式:使用共享对象,用来减少内存使用量,将大量重复对象变成一个共享的内存中,对于int类型数值,java默认一个字节的数值使用享元模式(同个地址)
//==比较的是地址,equals比较的是值
Integer x1 = new Integer(10);
Integer x2 = new Integer(10);
System.out.println(x1==x2);//false
System.out.prinlen(x1.equals(x2));//true
Integer x3 = new Integer(128);
Integer x4 = new Integer(128);
System.out.println(x3==x4);//false
System.out.println(x3.equals(x4));//true
Integer x5 = 10;
Integer x6 = 10;
System.out.println(x5==x6);//true(享元模式,共用一个地址上的常量)
System.out.println(x5.equals(x6));//true
Integer x7 = 128;
Integer x8 = 128;
System.out.println(x7==x8);//false(超出0-127一个字节,不被视为常用数,不使用享元模式)
System.out.println(x7.equals(x8));//ture
包与访问修饰符
包用于对多个java源文件管理,就如同目录
包的定义:(该语句只能出现在代码的第一句)
package com.vince
定义的包路径要与文件夹文件名、文件路径一致异常处理
Throwable
是所有异常的超类,分为Error和Exception,主要关注ExceptionException
分为编译期异常(受检)和运行期异常(非受检)- 开发中把可能出现异常的代码用
try,catch
语句包裹起来 - 当代码出现异常时,会产生异常对象(jdk或者JVM产生)
- try、catch
catch
可以有多个,顺序从子类到父类,范围广的放后面finally
(可选):作为程序的try部分的最终出口,不管最后有没有出错,都会执行- 测试时可以使用
x.printStackTrace()
打印出具体的异常信息
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
div(10,0);//运行时异常
}
public static void div(int num1,int num2) {
int[] arr = new int[] {1,2,3,4,5};
try{
System.out.println(arr[5]);
arr = null;
System.out.println(arr.length);
int result = num1/num2;
System.out.println(result);
}catch(ArithmeticException e) {
System.out.println("除数不能为0");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界");
}catch(NullPointerException e) {
System.out.println("空指针异常");
}catch(Exception e){
System.out.println("出错啦");
//代码测试时打印出异常信息
e.printStackTrace();
}finally{
//不管有没有出错,都会执行
//若上面try的语句存在return语句,系统会自动搜索是是否存在finally,若存在,则先执行完finally的语句才执行return
System.out.println("程序结束");
}
}
}
try,catch的另一种写法:
//try,catch的另一种写法:
try(...){
...
}catch(a|b e){
...
}
- throws、throw
throws主要用在方法的声明上,表示方法中不处理异常,交给调用处处理
throw手动抛出一个异常
public static int div(int a,int b) throws ArithmeticException{
try{
int c = a/b;
return c;
}catch(ArithmeticException e){
throw new ArithmeticException("除数不能为零");//更改报错类型
}
//这里不需要return,因为程序已经因异常终止
}
常见异常:
- ArithmeticException
- ArrayIndexOutOfBoundsException
- NullPointerException
- InputMismatchException
- ClassNotFoundException
- ClassCastException
- DataFormatException
- RuntimeException
自定义异常
- 通过继承
Exception
类的都是受检异常,继承RoutimeException
都是非受检异常 - 继承Exception都需要显式的使用try…catch…,继承RoutimeException的可以不调用,但通常仍要使用
- 自定义异常的实现,通常是提供构造方法,异常对象本身没有实际功能
public class MyException extends Exception{
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
assert关键字
表示断言,判断程序中某个变量是否是预期的结果
assert 语句
int result = 10+10;
assert result==20:"结果不正确";//如果结果不为20则报错
常用类库API
字符串操作 String类
- 两种赋值方式
String name1 = “xiaoming”;
String name2 = new String(“xiaomnig”);
存储机制:方法1在栈内存有指向堆内存的字符串常量池,方法2会先寻找常量池是否存在,若存在则只在堆内存创建一个对象,但若没有,会在堆内存创建一个对象,同时会在常量池创建一个字符串常量,name指向堆内存对象,而堆内存存储指向常量池的地址
String name3 = "xiaominig"
name1 == name2;//false
name1 == name3;//true
- 5种情况分析
变量的值只能在运行期才会被确定
如果在编译期可以确定,那么使用已有的对象,否则创建新的对象
(1) 情况1
String a = "a";//常量池编译期确定
String a1 = a+1;//运行期确定("a1")
String a2 = "a1";//常量池编译期确定
System.out.println(a1==a2);//false
(2) 情况2
final String b = "b";//final修饰的变量为静态,编译期确定
String b1 = b+"1";//编译期可以读取静态变量,编译期确定
String b2 = "b1";//编译期确定
System.out.println(b1==b2);//true
(3) 情况3
String c = getString();//通过方法取值,只能在运行期确定
String c1 = c+1;//运行期确定
String c2 = "c1";//编译期确定
System.out.println(c1==c2);//false
private static String getString(){
return "c";
}
(4) 情况4
final String d = getString();//虽然是个final常量,但是方法还是在运行期才确定
String d1 = d+1;
String d2 = "d1";
System.out.println(d1==d2);//false
private static String getString(){
return "d";
}
(5)情况5
String a = "a";
String b = "b";
String c = a+b+1;//运行时先产生a+b对象,再产生a+b+1对象
String d = "a"+"b"+1;//常量相加,只产生一个对象
- String类常用方法
public char charAt(int index)
:根据下标找到对应的字符public char[] toCharArray()
:以字符数组的形式返回全部字符串内容public String(char[] value)
:将全部的字符数组变为字符串public String(char[] value,int offset,int count)
:将指定范围的字符数组变为字符串public byte[] getBytes()
:将字符串变为字符数组public String(byte[] bytes)
:将字节数组变为字符串public String(byte[] bytes,int offset,int length)
:将指定范围的字节数组变为字符串public String(byte[] bytes,String charsetName)
:通过指定的charset解码指定的byte数组,构造一个新的Stringpublic boolean startsWith(String prefix)
:从第一个位置开始判断是否是以指定内容开头(prefix为正则表达式)public boolean startsWith(String prefix,int tooffset)
:从指定的位置开始判断是否是以指定内容开头public boolean endsWith(String suffix)
:判断是否是以指定内容结尾public String replace(char oldChar,char newChar)
:替换指定字符public String replace(CharSequence target,CharSequence replacement)
:替换指定字符串public String replaceAll(String regex,Stirng replacement)
:替换指定字符串public String replaceFirst(String regex,String replacement)
:替换第一个满足条件的字符串public String substring(int beginIndex)
:从指定位置开始一直截取到末尾public String substring(int beginIndex,int endIndex)
:截取指定范围的字符串public String[] split(String regex)
:按照指定的字符串拆分public String[] split(String regex,int limit)
:拆分字符串,并指定拆分的个数public boolean contain(String s)
:返回一个字符串是否存在public int indexOf(int ch)
:从头查找指定的字符是否存在,存在则返回位置,不存在返回-1;public int indexOf(int ch,int fromIndex)
:从指定诶之查找字符串是否存在,存在返回位置,不存在返回-1;public int inidexOf(String str)
:从头查找指定的字符串是否存在,存在返回位置,不存在返回-1public int indexOf(String str,int fromIndex)
:从指定位置查找字符串是否存在,存在返回位置,不存在返回-1public int lastIndexOf(int ch)
:从字符串的最后向前查找指定字符是否存在,存在返回位置,不存在返回-1public int lastIndexOf(int ch,int fromIndex)
:从指定的末尾开始查找指定字符是否存在,存在返回位置,不存在返回-1public int lastIndexOf(String str)
:从字符串的最后向前查找指定字符字符串是否存在,存在返回位置,不存在返回-1public int lastIndexOf(String str,int fromIndex)
:从指定的末尾开始查找指定字符串是否存在,存在返回位置,不存在返回-1public boolean isEmpty()
:判断内容是否为空public int length()
:获取字符串的长度public String toLowerCase()
:转小写public String toUpperCase()
:转大写public String trim()
:去掉开头和结尾的空格,中间的空格不去public String concat()
:字符串连接操作
StringBuffer类
- 主要是用于解决字符串拼接产生多个对象的性能问题
- StringBuffer的内部实现采用字符串数组,默认数组长度是16,超过时采用原长*2+2的方式扩充
- 当预知添加的数据长度时,建议使用带初始化容量的构造方法,避免动态扩充影响性能
- 该类是线程安全的,性能低
//append返回的仍然是StringBuffer对象
public class StringBufferDemo {
public static void main(String[] args) {
String a = "a";
String b = "b";
StringBuffer sb = new StringBuffer(17);
sb.append(a).append(b).append(1);
String d = sb.toString();
System.out.println(d);
}
}
- 常用方法:
public StringBuffer()
public StringBuffer(String str)
public StringBuffer(CharSequence seq)
public StringBuffer append(多种数据类型)
:字符串连接public StringBuffer delete(int start,int end)
public int indexOf(String str)
public StringBuffer insert int(offset,多种数据类型)
public StringBuffer replace(int start,int end,String str)
publci String substring(int start,int end)
:截取指定范围字符串public String substring(int start)
:字符串截取public StringBuffer reserve()
:字符串反转
StringBuilder
线程不安全的,性能高,适合单线程使用
字符串相加在编译后会使用该类优化代码实现拼接
程序国际化
Locale类
创建一个本地语言环境对象,该对象会根据参数设置来自动选择与之相关的语言环境
public class Locale{
public static void main(String[] args){
//第一个参数表示语言,第二个参数表示地区
Locale locale_CN = new Locale("zh","CN");
Locale locale_US = new Locale("en","US");
//使用默认方法会根据本地操作系统创建语言对象
Locale locale_Default = Locale.getDefault();//静态方法
}
}
ResourceBundle类
工具类不能用new
国际化通常的做法是将其定义成若干个属性文件(文件后缀为*.properties),属性文件中的格式采用”key=value”进行操作
info_en_US.properties
info_zh_CN.properties
ResourceBundle类表示的是一个资源文件的读取操作,所有资源文件需要使用该类进行读取,读取时不需要加上文件后缀
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Scanner;
public class InternationalDemo {
public static void main(String[] args) {
Locale locale_CN = new Locale("zh","CN");
Locale locale_US = new Locale("en","US");
Locale locale_defaul = Locale.getDefault();
Scanner input = new Scanner(System.in);
//通过工具类的静态方法getBundle获取文件信息
//用于绑定属性文件的工具类(参数:属性文件的基本名)
//不传第二个参数默认使用当前环境语言
//可以传第二个参数指定语言版本
ResourceBundle r = ResourceBundle.getBundle("info", );
//getString()方法从属性中使用key来获取value值
System.out.println(r.getString("system.name"));
System.out.println(r.getString("input.username"));
String username = input.nextLine();
System.out.println(r.getString("input.password"));
String password = input.nextLine();
if("admin".equals(username) && "123".equals(password)) {
System.out.println(r.getString("login.success"));
}else {
System.out.println(r.getString("login.error"));
}
}
}
//两个info文件
//info_zh_CN.properties
system.name = \u5458\u5DE5\u7BA1\u7406\u7CFB\u7EDF
input.username = \u8BF7\u8F93\u5165\u7528\u6237\u540D\uFF1A
input.password = \u8BF7\u8F93\u5165\u5BC6\u7801\uFF1A
login.success = \u767B\u5F55\u6210\u529F
login.error = \u767B\u5F55\u5931\u8D25
//info_en_US.propertises
system.name = EMP Manager System
input.username = Input UserName:
input.password = Input Password:
login.success = Login Success!
login.error = Login Error!
动态文本处理 java.text.MessageFormate类
该类继承于java.text.Format类,用于读取文本中不固定的量
//info_en_US.propertises
system.name = EMP Manager System
input.username = Input UserName:
input.password = Input Password:
login.success = Login Success!
login.error = Login Error!
welcome = welcome!{0}//不确定的量
String welcome = r.getString("welcome");
//第一个参数是文件中的key,第二个是该key中不确定量的value
welcome = MessageFormat.format(welcome, username);
Math类
数学运算方法,全是静态方法
使用Math类的两种方式:
- 直接使用(Math所在的java.lang为默认引入的包)
- 使用静态导入:
import static java.lang.Math.方法名
常用方法:
abs(double a)
:绝对值random()
:返回double类型随机数round(double a)
:返回最接近参数并等于某一整数的double值sqrt(double a)
:平方根
Random类
用于生成伪随机数流
非静态类,使用前要先new一个对象
Random r = new Random();
常用方法:
nextLong()
:返回下一个long类型随机数nextBoolean()
:返回一个随机boolean值nextDouble(),nextFloat()
:返回一个对应类型的随机数,在0.0和1.0之间nextInt(int n)
:参数可选,若无则范围为int的最大值,传参指定范围
Date类
表示特定的时间,精确到毫秒,也就是程序运行的当前时间
Date date = new Date();//当前时间
Date date = new Date(long data);//参数是毫秒Calendar类
日历类,将时间精确到毫秒
//两种使用方法
Calendar c1 = Calendar.getInstance();
Calendar c2 = new GregorianCalendar();
int year = c1.get(Calendar.YEAR);
int month = c1.get(Calendar.MONTH);
int day = c1.get(Calendar.DAY_OF_MONTH);
int hour = c1.get(Calendat.HOUR_OF_DAY);
int minute = c1.get(Calendar.MINUTE);
int second = c1.get(Calendar.SECOND);
int millisecond = c1.get(Calendar.MILLISECOND);
DateFormate类
抽象类
DateFormate df = new SimpleDateFormate("yyyy年MM月dd日 HH:mm:ss SSS");
String nowDate = df.format(new Date());
对象比较器
Array.sort()方法可以实现排序,但是当类对象里有多个变量时,无法比较,此时需要使用对象比较器进行指定
- Comparable接口
此接口强行对实现它的每个类进行整体排序,其中只有一个方法compareTo
,被称为自然比较法(sort方法继承了这个接口),所以要用这个比较,就需要先在被比较的类中继承该接口并实现,否则无法强制类型转换
//Comparable是泛型,可以指定类
class Cat implements Comparable<Cat>{
private String name;
private int age;
//省略构造方法
//实现接口中的方法
public int compareTo(Cat o){
//该方法用于比较此对象与指定对象的顺序,如果该对象小于,等于,大于指定对象,则分别返回负整数,零或正整数
return this.age-o.age;
}
}
Cat[] cats = {new Cat("小a",2),new Cat("小b",1),new Cat("小c",6)};
//此时可以进行比较
Arrays.sort(cats);
- Comparator接口
对于已经创建好的类,按照oo原则,对修改关闭,对扩展开放,所以可以使用Comparator接口重新定义一个新类来实现比较(该接口同样是泛型),该接口内有compare
方法
public class CatComparator implements Comparator<Cat>{
public int compare(Cat o1,Cat o2){
return o1.getAge()-o2.getAge();
}
}
//第一个参数是要比较的类,第二个是使用的比较器
Arrays.sort(cats,new CatComparator());
对象的克隆
在Object类中存在一个clone()方法:
protected Object clone() throws CloneNotSupportedException
被克隆的的对象需要实现Cloneable
接口,该接口是标记接口,没有任何方法,用于告诉虚拟机该类需要克隆
public class CloneDemo implements Cloneable{
//重写Object中的clone方法
protected Object clone() throws CloneNotSupportedException{
return super.clone;
}
}
Cat cat = new Cat("xiao",2);
try{
Cat newCat = (Cat)cat.clone();//因为返回的是object类型,所以要进行强制类型转换
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
克隆出来的对象因为是不同地址,所以不是同一个对象
System类
代表系统级的很多属性和控制方法
- 成员变量
in
out
error
:标准错误输出流(红色字体)
- 成员方法
arraycopy()
:参数分别是:源数组,源数组的起始位置,要复制的数组,目标数组的起始位置,长度
int[] num = {1,2,3,4,5};
int[] num1 = new int[num.length];
System.arraycopy(num,0,num1,,0,num.length);
currentTimeMillis()
返回当前计算机时间,时间为从1970年1月1日开始的毫秒数exit(int status)
退出JVM,其中status的值0表示表示正常退出,非零表示非正常退出gc()
:回收垃圾,一般不用getProperty(String key)
:获得系统中属性名为key的属性对应的值
Runtime类
使程序能够与其运行环境相连接
数字处理工具类
BigInter:对超过Integer范围的数据进行运算
BigDecimal:用于对小数点后多位的数据进行运算
- 构造方法:
public BigInter/BigDecimal(String val);
- 常用方法:add,subtract,multiply,divide,remainder(加减乘除求余)
DecimalFormat:格式化数据
double pi = 3.1415926
long num = 2334534543
//取一位整数,3
new DecimalFormat("0").format(pi);
new DecimalFormat("#").format(pi);
//取一位整数和两位小数,3.14
new DecimalFormat("0.00").format(pi);
//取两位整数和三位小数,03.142
new DecimalFormat("00.000").format(pi);
//以百分比计数,并取两位小数 314.16%
new DecimalFormat("#.##%").format(pi);
//以规定格式233,453,4543
new DecimalFormat("###,###").format(num);
MD5工具类
- 确认计算方法:
MessageDigest md5 = MessageDigest.getInstance("md5");
- 计算摘要:
byte[] bytes = md5.digest(password.getBytes("UTF-8"));
- 确认编码方式:
String newStr = Base64.getEncode().encodeToString(bytes);
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Md5Demo {
private static String password = "admin123";
private static String savePassword = "AZICOnu9cyUFFvBp3xi1AA==";// 最后编码后的字符串
public static void main(String[] args) {
//md5Test();
System.out.println(login("admin123456"));
}
private static boolean login(String password) {
if(savePassword.equals(md5Method(password))) {
return true;
}else {
return false;
}
}
private static String md5Method(String password) {
try {
MessageDigest md = MessageDigest.getInstance("md5");// 用于获取md5算法
// 通过md5进行摘要
byte[] bytes = md.digest(password.getBytes("UTF-8"));// 参数需要字节类型
String mdStr = new String(bytes);// 此时若输出mdStr会出现乱码,因为已经被md5算法打乱
// 对摘要进行编码
// a-z,A-Z,0-9,/,* (BASE64编码算法)
String str = Base64.getEncoder().encodeToString(bytes);
return str;// AZICOnu9cyUFFvBp3xi1AA==
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
private static void md5Test() {
String password = "admin123";
String savePassword = "AZICOnu9cyUFFvBp3xi1AA==";// 最后编码后的字符串
try {
MessageDigest md = MessageDigest.getInstance("md5");// 用于获取md5算法
// 通过md5进行摘要
byte[] bytes = md.digest(password.getBytes("UTF-8"));// 参数需要字节类型
String mdStr = new String(bytes);// 此时若输出mdStr会出现乱码,因为已经被md5算法打乱
// 对摘要进行编码
// a-z,A-Z,0-9,/,* (BASE64编码算法)
String str = Base64.getEncoder().encodeToString(bytes);
System.out.println(str);// AZICOnu9cyUFFvBp3xi1AA==
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
Lambda表达式
对于接口式匿名内部类,如果接口里只有一个方法,可以使用Lambda表达式替换
语法:(参数)->{具体方法}
当实现方法只有一条语句时可以省略大括号,有返回值且只有一条语句时直接写上返回值,如果参数需要使用修饰符,则必须完整写上所有修饰符
使用该表达式不会生成多余的class文件
public class LambdaDemo {
public static void main(String[] args) {
IEat1 ieat1 = ()->System.out.println("只有一条语句");
ieat1.eat();
IEat1 ieat2 = ()->{
System.out.println("eat apples");
System.out.println("多句话的写法");
};
ieat2.eat();
IEat2 ieat3 = (name)->{System.out.println("有参数的方式"+name);};
ieat3.eat("apple");
IEat3 ieat4 = ()->0;
System.out.println("相当于return 0 "+ieat4.eat());
IEat4 ieat5 = (final String name)->System.out.println("要写修饰符必须写全");
ieat5.eat("watermelon");
}
}
interface IEat1{
public void eat();
}
interface IEat2{
public void eat(String name);
}
interface IEat3{
public int eat();
}
interface IEat4{
public void eat(final String name);
}