- 成員內部類
- 局部內部類
- 匿名內部類
內部類的概念
特點:
-
編譯之后會生成獨立的字節碼文件
-
內部類可直接訪問外部類的私有成員,而不破壞封裝
-
可為外部類提供必要的內部功能組件
內部類是否會再次生成class文件?
答案是的
例如我自己寫了一個匿名內部類
class生成目錄下找到了
成員內部類
//成員內部類
public class Outer {
//實例變量
private String name = "張三";
private int age = 23;
//內部類
class Inner{
private String address = "hangzhou";
private String phone = "120";
//方法
public void show(){
//外部類
System.out.println(name);
System.out.println(age);
//內部類
System.out.println(address);
System.out.println(phone);
}
}
}
public class Test {
public static void main(String[] args) {
//創建外部類對象
Outer outer = new Outer();
//創建內部類對象
Outer.Inner inner = outer.new Inner();
//嫌麻煩可以換成這樣
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
//成員內部類
public class Outer {
//實例變量
private String name = "張三";
//內部類
class Inner{
private String name ="李四";
//方法
public void show(){
System.out.println(name);
//如果需要訪問內部類對象,改成這樣
System.out.println(Outer.this.name);
}
}
}
private static final String country = "中國";
靜態內部類
//靜態內部類
public class Staticc {
//私有屬性
private String name = "XXX";
private int age = 12;
//靜態內部類
static class Inner{
//靜態內部類中的私有屬性
private String address = "hangzhou";
private String phone = "120";
//靜態內部類中靜態的私有屬性
private static final String country = "中國";
public void show(){
Staticc staticc = new Staticc();
System.out.println(staticc.age);
System.out.println(Inner.country);
}
}
}
public class TestSt {
public static void main(String[] args) {
Staticc.Inner inner = new Staticc.Inner();
inner.show();
}
}
public class part {
//實例變量
private String name = "張三";
private int age = 23;
public void show(){
//定義局部變量
final String address="sz";
//局部類-局部內部類前面不能加任何訪問修飾符public
//局部變量 本身就是 一個訪問權限 的設定啊。 只能在局部調用
//定義在方法中的變量叫局部變量,局部變量的有效范圍就是方法內,在局部變量中加上public,或者其他修飾符的話(編譯都通不過),就破壞了局部變量的范圍,可以說局部變量是為方法而生的。局部變量中的局部就已經說明了范圍
class Inner{
private String address = "hangzhou";
private String email = "120";
public void show2(){
//訪問外部類屬性
System.out.println(part.this.age);
System.out.println(part.this.name);
//訪問內部類屬性
System.out.println(this.address);
System.out.println(this.email);
//調用局部變量
//在JDK1.7之前,變量必須加上final,JDK1.8后是自動添加的
System.out.println(address);
}
}
Inner inner = new Inner();
inner.show2();
}
}
final String address="sz";
匿名內部類
- 沒有類名的局部內部類(一切特征都與局部內部類相同)
- 必須繼承一個父類或者實現一個接口
public class TestUsb {
public static void main(String[] args) {
//使用匿名內部類
//定義類、實現類、創建對象的語法合並,只能創建一個該類的對象。
Usb usb = new Usb() {
@Override
public void Service() {
System.out.println("開始旋轉");
}
};
usb.Service();
}
}
優點:減少代碼量
缺點:可讀性太差
public class TestUsb {
public static void main(String[] args) {
//創建接口類型的變量
Usb usb = new Mouse();
usb.Service();
局部內部類
class Fan implements Usb{
@Override
public void Service() {
System.out.println("連接電腦成功!");
}
}
//使用局部內部類開始創建對象
Usb usb = new Fan();
usb.Service();
}
}
public interface Usb {
void Service();
}
public class Mouse implements Usb{
@Override
public void Service() {}
}
Object類
-
作為參數,可以接受任何對象
-
作為返回值,可返回任何對象
getClass()方法
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("li",11);
Student s2 = new Student("wang",23);
//判斷S1和S2是否是同意類型
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if (class1==class2){
System.out.println("same");
}else {
System.out.println("no same");
}
}
}
hashCode()方法
package commonclass.getclas;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("li",11);
Student s2 = new Student("li",11);
//打印哈希值
System.out.println("====================");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
//賦值給到新的變量時,哈希值也會被賦值過去
Student s3 = s1;
System.out.println(s3.hashCode());
System.out.println("====================");
}
}
輸出
1956725890
356573597
1956725890
====================
思考:equals未重寫時,比較的是內容還是內存地址?
equal是object類的方法,所有沒有重寫這個類的方法;比較的都是內存地址,和==是一樣的,重寫后該方法是按照重寫的方法來進行比較,比如String類就重寫了這個方法,比較的是內容。
如何將equals()方法進行覆蓋?
-
比較兩個引用是否指向同一個對象
-
判斷obj是否為null
-
判斷兩個引用指向的實際對象類型是否一致、
-
強制類型轉換
-
依次比較各個屬性值是否相同。
@Override
public boolean equals(Object o) {
//1、判斷兩個對象是否是同一引用
if (this==o){
return true;
}
//2、判斷o是否為null
if (o==null){
return false;
}
//3、判斷是否是同一類型
//第一種
// if(this.getClass()==o.getClass()){
//
// }
//第二種
if(o instanceof Student){
//4、強制類型轉換
Student s=(Student) o;
//5、比較各個屬性值是否相同
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
return false;
}
這是手寫的,可能存在bug,可以直接使用idea的快捷鍵alt+insert自動重寫equals
finalize()方法
作用:當對象被判定為垃圾對象時,由JVM自動調用此方法,用以標記垃圾對象,進入回收隊列。
思考:什么樣的對象會被判定為垃圾對象?
public class TestStudent2 {
public static void main(String[] args) {
//已經有指定的,無法直接回收
// Student s1 = new Student("a",1);
// Student s2 = new Student("b",1);
//無指定
new Student("c",1);
new Student("d",1);
//垃圾回收
System.gc();
System.out.println("已回收");
}
}
//重寫finalize方法
@Override
protected void finalize() throws Throwable {
System.out.println(this.name+"銷毀");
}
垃圾對象:沒有有效引用指向此對象時,為垃圾對象。
自動回收機制:JVM的內存耗盡,一次性回收所有垃圾對象。
手動回收機制:使用System.gc();通知JVM執行垃圾回收。
什么是包裝類?
裝箱和拆箱
基本數據類型存儲在棧中,引用數據類型是存儲在堆中
將堆中的對象放到棧中,就是拆箱
//自動裝箱和拆箱
public class Demo01 {
public static void main(String[] args) {
//JDK1.5之前的寫法
//裝箱操作、基本類型轉換引用類型
int num1 = 100;
//使用Integer創建對象,裝箱的兩種方法
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
System.out.println("裝箱");
System.out.println(integer1);
System.out.println(integer2);
//拆箱操作、引用類型轉換基本類型
Integer integer3 = new Integer(100);
int num2 = integer3.intValue();
System.out.println(num2);
System.out.println("===================");
//JDK1.5之后的寫法
//java提供了自動裝箱和拆箱
//自動裝箱
int age = 200;
Integer integer4 = age;
System.out.println(integer4);
//自動拆箱
int num3 = integer4;
System.out.println(num3);
}
}
8中包裝類提供不同類型間的轉換方式:
Number父類提供的6個共性方法
parseXXX()靜態方法---將字符串轉換成基本類型
valueOf靜態方法---裝箱操作,基本類型轉換成引用類型
注意:需保證類型兼容,否則容易拋出NumberFormatException異常
//字符串與基本類型的轉換
//基本類型轉換成字符串
int n1 = 20;
//1、使用+
String s1 = n1+"";
//2使用Integer的toString()方法
//radix轉換的進制
String s2 = Integer.toString(n1,16);
System.out.println(s1);
System.out.println(s2);
//字符串轉換成基本類型
String str = "100";
//使用Integer的parseXXX方法
int n2 = Integer.parseInt(str);
System.out.println(n2);
//boolean字符串轉換成基本類型
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(str2);
Interger緩沖區
Java預先創建了256個常用的整數包裝類型對象;
//關於Integer緩沖區的面試題
public class Demo02 {
public static void main(String[] args) {
//思考?是否相等
//不相等,==比較的是內存地址,
// Integer是引用類型在堆中,所以內存地址不同
Integer integer1 = new Integer(20);
Integer integer2 = new Integer(20);
System.out.println(integer1==integer2);
//思考?是否相等
//相等,相當於自動裝箱
//實際完整代碼:Integer integer3 = Integer.valueOf(30);
//對於valueOf是有在堆中提前設計的緩存區間,可以存儲-128-127之間的數字
Integer integer3 = 30;
Integer integer4 = 30;
System.out.println(integer3==integer4);
//思考?是否相等
//不相等。當范圍超出設計的緩存區間,會自動另外開辟新的空間,則為false
Integer integer5 = 300;
Integer integer6 = 300;
System.out.println(integer5==integer6);
}
}
String類
字符串是常量,創建之后不可改變;字符串字面存儲在字符串池中,可以共享。
String s1 = "Hello";產生一個對象,字符串池中存儲
public class Demo03 {
public static void main(String[] args) {
//注意這里修改的不是s1,而是在常量池中重新開辟了一個空間,叫wang
//s1也指向wang
String s1 = "lee";
s1 = "Wang";
//面試題
//思考:為什么是false?
//new是在堆中開辟新的空間,同時又指向常量池,相當於兩個地址
//==比較的是內存地址,所以返回false
String s2 = new String("Zhang");
String s3 = new String("Zhang");
System.out.println(s2==s3);
}
}
常用方法
//String方法
//1、length;返回字符串長度
//2、CharAt;返回某個位置的字符
//3、contain;判斷是否包含某個子字符串
String str1 = "王冰冰最美";
System.out.println(str1.length());
System.out.println(str1.charAt(str1.length()-1));
System.out.println(str1.contains("王"));
//4、toCharArray;返回字符串對應的數組
//5、iNdexOf;返回子字符串首次出現的位置
//6、lastIndexOf;返回字符串最后一次出現的位置
System.out.println(Arrays.toString(str1.toCharArray()));
System.out.println(str1.indexOf("冰"));
System.out.println(str1.lastIndexOf("冰"));
//7、trim();去電字符串前面的空格
//8、toUpperCase()/toLowerCase();把小寫轉換成大寫,大寫轉小寫
//9、endWith()/startsWith();是否是以str結尾;或開頭
String str2 = " wangbingBingzuimei ";
System.out.println(str2.trim());
System.out.println(str2.toUpperCase());
System.out.println(str2.toLowerCase());
String str3 = "wangbingbing";
System.out.println(str3.endsWith("bing"));
System.out.println(str3.startsWith("wang"));
//10、replace();用新的字符串替換舊的字符或字符串
//11、split();對字符串拆分
String str4 = "[wangbingbing shi ,zui mei de]";
System.out.println(str4.replace("wang","li"));
//加上[] 意味着,可以同時分離空格和逗號(正則表達式)
//+ 意味着出現多個空格和逗號都可以去除
String[] arr = str4.split("[ ,]+");
System.out.println(arr.length);
for (String s:arr
) {
System.out.print(s);
}
//12、補充兩個方法equals()、compareTo();
String str5 = "hello";
String str6 = "HELLO";
//equalsIgnoreCase()忽視字母大小進行比較
System.out.println(str5.equalsIgnoreCase(str6));
//compareTo()長度一樣,依次比較的是字符
String str7 = "abc";
String str8 = "xyz";
System.out.println(str7.compareTo(str8));
//長度不一樣,就比長度
String str9 = "abc";
String str10 = "abcbnm";
System.out.println(str9.compareTo(str10));
StringBuffer和StringBuilder
StringBuffer:可變長字符串,JDK1.0提供,運行效率低,線程安全,用於多線程
/**
* StringBuffer和StringBuilder
* 和String區別
* 1、效率比String更高
* 2、比String更節省內存
*/
public class Demo04 {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
//1、append()、追加
sb.append("wangbingbing");
System.out.println(sb);
sb.append("zuimei");
System.out.println(sb.toString());
//2、insert()、插入
sb.insert(0,"woshuo");
System.out.println(sb.toString());
//3、replace()、替換
sb.replace(0,2,"ni");
System.out.println(sb.toString());
//4、delete()、刪除
sb.delete(0,6);
System.out.println(sb.toString());
sb.delete(0,sb.length());
System.out.println(sb.length());
}
}
/**
* 證明StringBuilder效率高於String
*差距是真的大
*/
public class Demo05 {
public static void main(String[] args) {
//開始時間
long start = System.currentTimeMillis();
// String string = "";
// //String的用時
// for (int i = 0; i < 99999; i++) {
// string+=i;
// }
// System.out.println(string);
//StringBuilder的用時
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 99999; i++) {
sb.append(i);
}
System.out.println(sb);
//結束時間
long end = System.currentTimeMillis();
System.out.println("用時"+(end-start));
}
}
輸出結果:
StringBuilder:用時19
StringBuffer:用時22036
作用:精確計算浮點數
/**
* BigDecimal的作用
*/
public class Demo06 {
public static void main(String[] args) {
//思考?為什么結果不是准確的
//double是近似值存儲,不符合要求,需要借助BigDecimal
double d1 = 1.0;
double d2 = 0.9;
System.out.println(d1-d2);
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("0.9");
//減法
BigDecimal r1 = bd1.subtract(bd2);
System.out.println(r1);
//加法
BigDecimal r2 = bd1.add(bd2);
System.out.println(r2);
//乘法
BigDecimal r3 = bd1.multiply(bd2);
System.out.println(r3);
//除法
//1.4-0.5/0.9
BigDecimal r4 = new BigDecimal("1.4")
.subtract(new BigDecimal("0.5"))
.divide(new BigDecimal("0.9"));
System.out.println(r4);
//除法涉及到的近似值
BigDecimal r5 = new BigDecimal("10").divide(new BigDecimal("3"),3,BigDecimal.ROUND_HALF_UP);
System.out.println(r5);
}
}
在計算除法時
除法:.divide(new BigDecimal("3"),scal,RoundingMode mode);
參數
scal:指定小數點精確到小數點后幾位
mode:
Date類
-
1秒=1000毫秒
-
1毫秒=1000微秒
-
1微秒=1000納秒
/**
* Date方法
*
*/
public class Demo07 {
public static void main(String[] args) {
//創建對象
Date date1 = new Date();
//當前時間
System.out.println(date1.toString());
System.out.println(date1.toLocaleString());
//昨天時間
Date date2 = new Date(date1.getTime()-60*60*24*1000);
System.out.println(date2.toLocaleString());
//方法after before
boolean b1 = date1.after(date2);
System.out.println(b1);
boolean b2 = date1.before(date2);
System.out.println(b2);
//比較CompareTo()
int d = date2.compareTo(date1);
System.out.println(d);
//比較是否相等equals()
boolean b3 = date1.equals(date2);
System.out.println(b3);
}
}
Calendar類
作用:Calendar提供了獲取或設置各種日歷字段的方法
/**
* Calendar類
*/
public class Demo08 {
public static void main(String[] args) {
//因為Calendar修飾符是protected,所以無法new
//1、創建對象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toLocaleString());
System.out.println(calendar.getTimeInMillis());
//查看時間
//年
int year = calendar.get(Calendar.YEAR);
//月
int month = calendar.get(Calendar.MONTH);
//日
int day = calendar.get(Calendar.DAY_OF_MONTH);
//HOUR_OF_DAY代表24小時制
int hour = calendar.get(Calendar.HOUR_OF_DAY);
//分
int minute = calendar.get(Calendar.MINUTE);
//秒
int second = calendar.get(Calendar.SECOND);
System.out.println("年" + year +
"月" + month +
"日" + day +
"時" + hour +
"分" + minute +
"秒" + second);
//3、set方法修改時間
Calendar calendar1 = Calendar.getInstance();
calendar1.set(Calendar.DAY_OF_MONTH,5);
System.out.println(calendar1.getTime().toLocaleString());
//4、add方法修改時間
calendar1.add(Calendar.HOUR_OF_DAY,-1);
System.out.println(calendar1.getTime().toLocaleString());
//5、補充方法,查看參數的最大值
int max = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH);
int min = calendar1.getActualMinimum(Calendar.DAY_OF_MONTH);
System.out.println(max);
System.out.println(min);
}
}
SimpleDateFormat類
進行格式化(日期->文本)、解析(文本->日期)
public class Demo09 {
public static void main(String[] args) throws ParseException {
//1、創建SimpleDateFormat對象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
//創建Date
Date date = new Date();
//格式化date 把日期轉換成字符串
String s1 = simpleDateFormat.format(date);
System.out.println(s1);
//解析,格式要與simpleDateFormat規定的格式相同
Date date1 = simpleDateFormat.parse("2002-02-02 10-11-11");
System.out.println(date1);
}
}
System類
/**
* System類
*/
public class Demo10 {
public static void main(String[] args) {
//1、arraycopy:數組的復制
//src:原數組
//srcPos:從原數組哪個位置開始復制
//dest:目標數組
//destPos:從目標數組的哪個位置開始粘貼
//length:復制的長度
int[] arr1 = {1,2,3,4,56,6};
int[] arr2 = new int[8];
System.arraycopy(arr1,0,arr2,0,6);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
// Arrays.copyOf();還是使用的System.arraycopy,
//2、復制當前系統時間
long start = System.currentTimeMillis();
for (int i = 0; i < 99999999; i++) {
for (int j = 0; j < 99999999; j++) {
int result = i+j;
}
}
long end = System.currentTimeMillis();
System.out.println("用時:"+(end-start));
//3、建議JVM啟動垃圾回收器回收垃圾
System.gc();
//4、退出JVM如果參數為0,正常退出,非0表示異常退出
System.exit(0);
System.out.println("上面喊收工了,后面就不執行了");
}
}