Object类
Object类是所有Java类的根基类,也就意味着所有的Java对象都拥有Object类的属性和方法。
如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。
Object类中定义了一些JAVA所有的类都必须具有的一些方法
简介
常用方法(public) | |
---|---|
boolean | equals(Object obj) 指示其他某个对象是否与此对象“相等”。 |
Class | getClass() 返回此 Object 的运行时类。 |
int | hashCode() 返回该对象的哈希码值。 |
void | notify() 唤醒在此对象监视器上等待的单个线程。 |
void | notifyAll() 唤醒在此对象监视器上等待的所有线程。 |
String | toString() 返回该对象的字符串表示。 |
void | wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 |
void | wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。 |
void | wait(long timeout, int nanos) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 |
方法摘要 | |
---|---|
protected Object | clone() 创建并返回此对象的一个副本。 |
protected void | finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 |
扩展:native关键字
一个native方法就是一个Java调用非Java代码的接口。一个native方法是指该方法的实现由非Java语言实现,比如用C或C++实现。
在定义一个native方法时,并不提供实现体,因为其实现体是由非Java语言在外面实现的。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
JNI是Java本机接口(Java Native Interface),是一个本机编程接口,它是Java软件开发工具箱(Java Software Development Kit,SDK)的一部分。JNI允许Java代码使用以其他语言编写的代码和代码库。Invocation API(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用Java代码。
==和equals方法
“==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。显然,这无法满足子类的要求,可根据要求重写equals方法。
public class Test1 {
public static void main(String[] args) {
/*
* ==
* 两端如果是基本数据类型,那么就是单纯判断值是否相同
* 两端是引用类型,那么判断的引用的地址是否相同,判断是否指向内存上的同一个数据
* */
int a=10;
int b=10;
System.out.println(a==b); //true
String s =new String("asdf");
String s2=new String("asdf");
System.out.println(s);
System.out.println(s2);
System.out.println(s==s2); //false
String s3="abc";
String s4="abc";
System.out.println(s3==s4); //true
System.out.println(s.equals(s2)); //true
System.out.println(s3.equals(s4)); //true
}
}
重写默认方法
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
//使用 alt+insert 快捷键即可
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
// 只要对象的属性值相同,返回的哈希码就是相同的
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class test {
public static void main(String[] args) {
String a = "a";
String b = "b";
String c = "c";
String d = "d";
String str = a+b+c+d;
String str2 = "abcd";
String str3 = "a"+"b"+"c"+"d";
System.out.println(str == str2); //false
System.out.println(str == str3); //false
System.out.println(str2 == str3); //true
}
}
//==是比较地址值 使用变量相加每次都会执行 new String()操作在堆空间创建 而非直接指向字符串常量池
包装类
Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但我们在实际应用中经常需要将基本数据转化成对象,以便于操作。
为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
分类
8种基本数据类型,分别对应一个包装类。包装类均位于java.lang包
基本数据类型 | 包装类 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
八个类名中,除了Integer和Character类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写而已
八个类中,除了Character和Boolean以外,其他的都是“数字型“,“数字型”都是java.lang.Number的子类。
public class TestWrapper1 {
int num;
Integer in ;
public static void main(String[] args) {
//1.某些方法参数是对象,为了让基本数据类型能作为参数
List<Object> list = new ArrayList<>();
list.add(new Integer(56)); //int 56
list.add(new Integer(100));
list.add(new Double(67.5));
System.out.println(list);
//2.包装类还可以提供更多的功能
System.out.println(Integer.SIZE);
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.toBinaryString(123));
System.out.println(Integer.toOctalString(123));
System.out.println(Integer.toHexString(123));
//3.其他特别重要的功能:可以实现字符串和基本数据类型之间的转换
String str = "123"; //----123
int num2 = Integer.parseInt(str);
System.out.println(num2);
String str2 = "123.45";
double d = Double.parseDouble(str2);
System.out.println(d);
}
}
注意:
1. 包装类的对象需要占用栈内存和堆内存,而基本数据类型的(局部)变量只占用栈内存;基本数据类型的变量占用空间少,更简单,更灵活,更高效。
2. 作为成员变量,初始值不同。int 0;Integer null。
自动拆箱装箱
public static void main(String[] args) {
String str ="222";
int n = Integer.parseInt(str);
Integer integer = Integer.valueOf(str);
String s = Integer.toString(integer);
System.out.println("--------------手动装箱 拆箱--------");
int a = 10;
Integer inter = new Integer(a); //手动装箱
int i = inter.intValue(); //手动拆箱
System.out.println("--------jdk1.5自动装箱 拆箱---------");
int b = 10;
Integer integer1 = b;
int i1 = integer1;
System.out.println("--------------隐藏装箱 拆箱---------");
Integer c = new Integer(10);
c++; //转int
int cc=10;
c.equals(cc); //转Integer
}
IntegerCache
integer类提供了一个静态内部类IntegerCache,对于定义一个静态数组cache,长度为256,赋值为-128—127。对于自动装箱时如果是-128—127范围内的数据,直接获取数组的指定值;对于这个范围之外的数据,通过new Integer()重新创建对象。这么做的目的是提高效率。
public static void main(String[] args) {
Integer integer1 = 40;
Integer integer2 = 40;
System.out.println(integer1==integer2);//ture
Integer integer3 = 200;
Integer integer4 = 200;
System.out.println(integer3==integer4);//false
}
总结
1. JDK1.5以后,增加了自动装箱与拆箱功能,如:Integer i = 100; int j = new Integer(100);
2. 自动装箱调用的是valueOf()方法,而不是new Integer()方法。
3. 自动拆箱调用的xxxValue()方法。
4. 包装类在自动装箱时为了提高效率,对于-128~127之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用equals方法。
字符串相关类
String类、StringBuilder类、StringBuffer类是三个字符串相关类。String类代表不可变的字符序列,StringBuilder类和StringBuffer类代表可变字符序列。
String类
常用方法
char | charAt(int index) 返回指定索引处的 char 值。 |
---|---|
int | compareTo(String anotherString) 按字典顺序比较两个字符串。 |
String | concat(String str) 将指定字符串连接到此字符串的结尾。 |
boolean | contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列时,返回 true。 |
boolean | endsWith(String suffix) 测试此字符串是否以指定的后缀结束。 |
boolean | equals(Object anObject) 将此字符串与指定的对象比较。 |
boolean | equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。 |
int | hashCode() 返回此字符串的哈希码。 |
int | indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。 |
int | indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。 |
int | indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。 |
int | indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。 |
boolean | isEmpty() 当且仅当 length() 为 0 时返回 true。 |
int | lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。 |
int | lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定索引处开始进行反向搜索。 |
int | lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。 |
int | lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 |
int | length() 返回此字符串的长度。 |
String | replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 |
String | replace(CharSequence target, CharSequence replacement) 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 |
String | replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
String[] | split(String regex) 根据给定正则表达式的匹配拆分此字符串。 |
boolean | startsWith(String prefix) 测试此字符串是否以指定的前缀开始。 |
boolean | startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 |
String | substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。 |
String | substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。 |
String | toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 |
String | toString() 返回此对象本身(它已经是一个字符串!)。 |
String | toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 |
String | trim() 返回字符串的副本,忽略前导空白和尾部空白。 |
注意
JDK9以前 String 底层是一个char类型的数组,所有的操作都是针对char数组完成。
JDK9及其以后底层采用的是 byte类型的数组
String底层会自动的判断当前存入的是什么类型,如果存入的字符串都是英文/数字/符号啥的。这些都会占用一个字节
一旦存入的字符串中含有了中文这个时候,字符串中每一个字符都占用两个字节
每执行一次字符串连接操作底层都会创建一个新的数组 因此效率很低
StringBuilder与StringBuffer
StringBuffer和StringBuilder非常类似,均代表可变的字符序列。这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。
两个类的主要区别:
1. StringBuffer JDK1.0提供的类,线程安全,做线程同步检查,效率较低。
2. StringBuilder JDK1.5提供的类,线程不安全,不做线程同步检查,因此效率较高。 建议采用该类。
public class StringBuilt {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("beijing");
// StringBuffer stringBuilder = new StringBuffer("beijing");
//字符串追加
stringBuilder.append("cp");
stringBuilder.append(1).append(2).append("aa");
stringBuilder.insert(3, "a");
stringBuilder.setCharAt(3, 's');
stringBuilder.replace(1, 3, "bbb");
stringBuilder.delete(1, 3);
stringBuilder.reverse();
//string 转换
String str = "beijing";
StringBuilder builder = new StringBuilder(str);
String string = builder.toString();
}
}
StringBuilder | append(boolean b) 将 boolean 参数的字符串表示形式追加到序列。 |
---|---|
int | capacity() 返回当前容量。 |
char | charAt(int index) 返回此序列中指定索引处的 char 值。 |
StringBuilder | delete(int start, int end) 移除此序列的子字符串中的字符。 |
StringBuilder | deleteCharAt(int index) 移除此序列指定位置上的 char。 |
void | ensureCapacity(int minimumCapacity) 确保容量至少等于指定的最小值。 |
int | indexOf(String str) 返回第一次出现的指定子字符串在该字符串中的索引。 |
int | indexOf(String str, int fromIndex) 从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。 |
StringBuilder | insert(int offset, boolean b) 将 boolean 参数的字符串表示形式插入此序列中。 |
int | lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。 |
int | lastIndexOf(String str, int fromIndex) 返回最后一次出现的指定子字符串在此字符串中的索引。 |
int | length() 返回长度(字符数)。 |
StringBuilder | replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。 |
StringBuilder | reverse() 将此字符序列用其反转形式取代。 |
String | substring(int start) 返回一个新的 String,它包含此字符序列当前所包含字符的子序列。 |
String | substring(int start, int end) 返回一个新的 String,它包含此序列当前所包含字符的子序列。 |
String | toString() 返回此序列中数据的字符串表示形式。 |
注意
StringBuilder类底层和String类一样,也是一个字节数组value,但不是final的。变量count表示的是底层字符数组的元素的真实个数,不是底层字符数组的长度。
默认数组的长度是16。也可以通过构造方法直接指定初始长度。length()方法返回的是字符数组元素的真实个数,capacity()返回的是底层数组的长度;
每次添加字符串时数组长度不够要扩容,扩容的默认策略时候增加到原来长度的2倍再加2
//部份源码
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder; //coder 中文为1 其他为0
//默认策略:数组原来长度的2倍+2
int newCapacity = (oldCapacity << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
其他常用类
日期类
Date
Date类中的很多方法都已经过时了。JDK1.1之前的Date包含了:日期操作、字符串转化成时间对象等操作。JDK1.1之后,日期操作一般使用Calendar类,而字符串的转化使用DateFormat类。
public class TestDate {
public static void main(String[] args) {
System.out.println("---------java.util.Date---------");
Date date = new Date(); //2022-3-16
System.out.println(date.getYear());//122 1990+122
System.out.println(date.getMonth()); //2 从0开始
System.out.println(date.getDate()); //16
System.out.println("---------获取毫秒--------");
System.out.println(date.getTime());
System.out.println(System.currentTimeMillis());
System.out.println("---------java.sql.Date---------");
String str = "2022-8-4";
java.sql.Date date1 = java.sql.Date.valueOf(str);
System.out.println(date1);
}
}
DateFormat
DateFormat是一个抽象类,一般使用它的的子类SimpleDateFormat类来实现。主要作用就是把时间对象转化成指定格式的字符串。反之,把指定格式的字符串转化成时间对象。
public class TestDateFormat {
public static void main(String[] args) throws ParseException {
//string 转date
String str = "2022/9/20 13:12:12";
DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = format.parse(str);
System.out.println(date);
//date 转string
Date date1 = new Date();
DateFormat format1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String s = format1.format(date1);
System.out.println(s);
}
}
字母 | 日期或时间元素 | 表示 | 示例 |
---|---|---|---|
G | Era 标志符 | Text | AD |
y | 年 | Year | 1996; 96 |
M | 年中的月份 | Month | July; Jul; 07 |
w | 年中的周数 | Number | 27 |
W | 月份中的周数 | Number | 2 |
D | 年中的天数 | Number | 189 |
d | 月份中的天数 | Number | 10 |
F | 月份中的星期 | Number | 2 |
E | 星期中的天数 | Text | Tuesday; Tue |
a | Am/pm 标记 | Text | PM |
H | 一天中的小时数(0-23) | Number | 0 |
k | 一天中的小时数(1-24) | Number | 24 |
K | am/pm 中的小时数(0-11) | Number | 0 |
h | am/pm 中的小时数(1-12) | Number | 12 |
m | 小时中的分钟数 | Number | 30 |
s | 分钟中的秒数 | Number | 55 |
S | 毫秒数 | Number | 978 |
z | 时区 | General time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | 时区 | RFC 822 time zone | -0800 |
Calendar
Calendar 类是一个抽象类,为我们提供了关于日期计算的相关功能,比如:年、月、日、时、分、秒的展示和计算。GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。
public class TestCalendar {
public static void main(String[] args) {
Calendar cal = new GregorianCalendar();
System.out.println(cal);
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH));
System.out.println(cal.get(Calendar.DAY_OF_MONTH));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
//设置时间
cal.set(Calendar.YEAR, 1992);
System.out.println(cal);
//calendar与date 转换
Date date = new Date();
cal.setTime(date);
System.out.println(date);
Date date1 = cal.getTime();
System.out.println(date1);
}
}
Math
java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double型。如果需要更加强大的数学运算能力,计算高等数学中的相关内容,可以使用apache commons下面的Math类库。
public static void main(String[] args) {
System.out.println(Math.PI);
System.out.println(Math.round(3.14));
System.out.println(Math.ceil(3.14));
System.out.println(Math.floor(3.14));
System.out.println(Math.sqrt(64));//开平方
System.out.println(Math.pow(2,5));//幂
System.out.println(Math.abs(-5));
System.out.println(Math.max(30,40));
System.out.println(Math.min(30,40));
System.out.println(Math.random());//[0.0,1.0)
}
Random
math类中虽然为我们提供了产生随机数的方法Math.random(),但是通常我们需要的随机数范围并不是[0, 1)之间的double类型的数据,这就需要对其进行一些复杂的运算。如果使用Math.random()计算过于复杂的话,我们可以使用例外一种方式得到随机数,即Random类,这个类是专门用来生成随机数的,并且Math.random()底层调用的就是Random的nextDouble()方法。
public static void main(String[] args) {
//Random rand = new Random(10000);
Random rand = new Random();
System.out.println(rand.nextInt());
System.out.println(rand.nextInt(10));
System.out.println(rand.nextDouble());
System.out.println(rand.nextFloat());
for (int i = 0; i < 10; i++) {
System.out.print(rand.nextInt(10)+" ");
}
}
枚举
定义枚举要使用enum关键字。对于性别、季节、星期几等内容,如果定义为字符串类型,是很难限制其取值的。
public enum Gender {
男,女
}
public class Person {
String name;
//String sex;//gender
Gender sex;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person person = new Person();
//person.sex = "adfadfad";
person.sex = Gender.男;
System.out.println(person.getSex());
}
}
public enum Season {
春,夏,秋,冬
}
public class TestSeason {
public static void main(String[] args) {
Season season = Season.夏;
switch(season){
case 春 :
System.out.println("春暖花开 踏青 春游 ");
break;
case 夏 :
System.out.println("夏日炎炎 吃雪糕 游泳");
break;
case 秋 :
System.out.println("秋高气爽 收庄稼 赏月");
break;
case 冬 :
System.out.println("冬雪皑皑 泡温泉 打雪仗");
break;
}
}
}