Python將字典(dict)轉化為Dataframe
簡稱
類都對應於一個獨立的Java原始檔,但是一個類還可以放在另一個類的內部,稱之為內部類,相對而言,包含它的類稱為外部類
一般而言,內部類與包含它的外部類有比較密切的關係,而與其他類關係不大,定義在類內部,可以實現對外部完全隱藏
可以有更好的封裝性,程式碼實現上也往往更為簡潔
內部類只是Java編譯器的概念,對於java虛擬機器而言,它是不知道內部類的,每個內部類最後都會被編譯為一個獨立的類,生成一個獨立的位元組碼檔案
靜態內部類
示例
public class StaticInner { private static int shared=100; public static class In{ public void inMethod(){ System.out.println("inner"+shared); } } public void test(){ In in = new In(); in.inMethod(); } }
靜態內部類除了位置上在其他類內部外,與一個獨立類差別不大,可以有靜態變數、靜態方法、成員方法、成員變數、構造方法等。
靜態內部類與外部內部類的關係不大。它可以訪問外部類的靜態方法和變數,但不可以訪問例項 變數和方法
public修飾的靜態內部類可以被外部使用,不過需要通過"new 外部類.靜態內部類"的方式
StaticInner.In in = new StaticInner.In(); in.inMethod()
顯示原理
public class StaticInner { private static int shared = 100; public void test(){ StaticInner$In si = new StaticInner$In(); si.inMethod(); } static int access$0(){ return shared; } } public class StaticInner$In { public void inMethod() { System.out.println("inner " + StaticInner.access$0()); } }
內部類訪問了外部類的一個私有靜態變數shared,因為私有靜態變數是不能被類外部訪問的
java的解決方法是:自動為StaticInner生成一個非私有訪問方法access$0,然後返回私有靜態變數
例子
Integer類內部有一個私有靜態內部類IntegerCache,用於支援整數的自動裝箱
LinkedList類內部有一個私有靜態內部類Node,表示連結串列中的節點
Character類內部有個一public靜態內部類UnicodeBlock,用於表示一個Unicode block
成員內部類
示例
public class MemberInner { private int a=100; public class In{ public void inMethod(){ System.out.println("outer a"+a); MemberInner.this.action(); } } private void action(){ System.out.println("action"); } public void test(){ In in = new In(); in.inMethod(); } }
成員內部類如果是例項除了可以直接訪問外部靜態變數和方法,還可以直接訪問外部例項變數和方法
如果是靜態則只能訪問外部靜態變數和方法。
成員內部類還可以通過"外部類.this.xxx"的方法引用外部類的例項變數和方法,這中寫法一般是在重名的情況下使用,如果沒有重名,那麼這種寫法是多餘的。
在外部類中,使用成員內部類和靜態內部類都是一樣的直接使用new。
與靜態內部類不同,"成員內部類物件總是與一個外部類物件相連的",在使用時不能直接通過new MemberInner.In(),而是要建立一個MemberInner物件
MemberInner m=new MemberInner(); m.In.in=m.new In();
與靜態內部類不同,成員內部類中不可以定義靜態變數和方法(final變數例外,它等同於常量)
成員內部類是與外部例項相連的,不應獨立使用,而靜態變數和方法作為型別的屬性和方法,一般是獨立使用的,在成員內部類中的 意義不大
如果成員內部類確實需要靜態變數和方法,也可以在外部定義
顯示原理
public class MemberInner {
private int a = 100;
private void action() {
System.out.println("action");
}
public void test() {
MemberInner$In inner = new MemberInner$In(this);
inner.innerMethod();
}
static int access$0(MemberInner memberInner) {
return outer.a;
}
static void access$1(MemberInner memberInner) {
MemberInner.action();
}
}
public class MemberInner$In {
final MemberInner memberInner;
public MemberInner$In(MemberInner memberInner){
ths.memberInner = memberInner;
}
public void innerMethod() {
System.out.println("outer a " + MemberInner.access$0(outer));
MemberInner.access$1(outer);
}
}
MemberInner\(In類有個例項變數memberInner指向外部類的物件,他在構造方法中被初始化
MemberInner在新建MemberInner\)In物件時給它傳遞了當前物件,由於內部類訪問了外部類的私有變數和方法
外部類MemberInner生成了兩個非私有靜態方法:access&0用於訪問變數a,access&1用法訪問方法action
如果內部類和外部類關係密切,需要訪問外部類的例項變數或方法,則可以考慮定義為成員內部類。
外部類的一些方法的返回值可能是某個介面,為了返回這個介面,外部類方法可能使用內部類實現這個介面,這個內部類可以設為private對外隱藏
例子
在LinkedList中,它的listIterator和descendingIterator的返回值都是介面Iterator,可以通過Iterator介面對連結串列遍歷
listIterator和descend-ingIterator內部分別使用了成員內部類ListItr和DescendingIterator,這兩個內部類都實現了介面Iterator
方法內部類(區域性內部類)
public class MethodInner {
private int a=100;
public void test(final int param){
final String str="hello";
class In{
public void inMethod(){
System.out.println("methodInner a"+a);
System.out.println("param"+param);
System.out.println("local var"+str);
}
}
In in = new In();
in.inMethod();
}
}
類In定義在外部類方法test中,方法內部類只能在定義的方法內被使用,如果方法是例項方法,則除了靜態變數和方法,方法內部類還可以直接訪問外部類的例項變數和方法。
如果test方法是靜態方法,則方法內部類只能訪問外部類中的靜態方法和變數。
方法內部類可以直接訪問方法的引數和方法中的區域性變數,不過必須宣告為final。
原理
public class MethodInner {
private int a = 100;
public void test(final int param) {
final String str = "hello";
In inner = new In(this, param);
inner.innerMethod();
}
static int access$0(MethodInner methodInner){
return MethodInner.a;
}
}
public class In {
MethodInner methodInner;
int param;
In(MethodInner methodInner, int param){
this.methodInner = methodInner;
this.param = param;
}
public void innerMethod() {
System.out.println("outer a " + MethodInner.access$0(this.methodInner));
System.out.println("param " + param);
System.out.println("local var " + "hello");
}
}
與成員內部類類似,In類也有一個例項變數methodInner來指向外部物件,在構造方法中被初始化,對外部私有例項變數的訪問也是通過methodInner新增的方法access$0來進行
方法內部類可以訪問方法中的引數和區域性變數,這是通過在構造方法中傳遞引數來實現的,如In構造方法中有引數int param,在新建In物件時,外部類將方法中的引數傳遞給了內部類。
String str沒有作為引數傳遞,因為被定義為了常量,在生成的程式碼中可以直接使用它的值
這就解釋了為什麼方法內部類訪問外部方法中的引數和區域性變數時,必須為final修飾的
方法內部類操作的並不是外部變數,而是它自己的例項變數,只是這些變數的值和外部變數一樣,對這些變數賦值並不會改變外部的值,為避免混淆直接定義為final
如果的確需要修改外部變數,可以將外部變數改為只含該變數的陣列,修改陣列中的值。
public class MethodInner {
public void test(){
final String[] str = new String[]{"hello"};
class In {
public void innerMethod(){
str[0] = "hello world";
}
}
In inner = new In();
inner.innerMethod();
System.out.println(str[0]);
}
}
str是一個只含一個元素的陣列,方法內部類不能改變str本身,但是可以修改它陣列的元素
例子
方法內部類可以用成員內部類替換,至於方法引數,也可以作為引數傳遞給成員內部類,如果類只在某個方法內被使用,則方法內部類可以更好的封裝。
匿名內部類
匿名內部類沒有單獨的類定義,他在建立物件的同時定義類
new 父類(引數){//匿名內部類實現}
或者 new 父介面(){//匿名內部類實現 }
public class AnonymousInner {
public void test(final int x,final int y){
Anonymous anonymous=new Anonymous(2,3){
@Override
public double distance() {
return distance(new Anonymous(x,y));
}
};
System.out.println(anonymous.distance());
}
}
public class Anonymous {
private int x;
private int y;
public double distance(){
return x+y;
}
public double distance(Anonymous anonymous){
return x+y;
}
public Anonymous(int x,int y){
this.x=x;
this.y=y;
}
}
匿名內部類只能被使用一次,用來建立一個物件。它沒有名字,沒有構造方法。但可以根據引數,呼叫對應的父類構造方法。
它可以定義例項變數和方法,可以有初始程式碼塊,初始程式碼塊可以起到無參構造方法的作用,但是初始程式碼塊只能由一個。
和方法內部類一樣,當方法是例項時,可以呼叫外部類所有的變數和方法,也可以訪問方法中的final引數和區域性變數
原理
public class AnonymousInner {
public void test(final int x, final int y){
Anonymous p = new AnonymousInner$1(this,2,3,x,y);
System.out.println(p.distance());
}
}
public class AnonymousInner$1 extends Anonymous {
int x2;
int y2;
AnonymousInner anonymousInner;
AnonymousInner$1(AnonymousInner anonymousInner, int x1, int y1, int x2, int y2){
super(x1,y1);
this.anonymousInner = anonymousInner;
this.x2 = x2;
this.y2 = y2;
}
@Override
public double distance() {
return distance(new Anonymous(this.x2,y2));
}
}
與方法內部類類似,外部例項this,方法引數x和y都作為引數傳遞給了內部類構造方法。此外,new時引數2和3也傳遞給了構造方法,內部類構造方法又將它們傳遞給了父類構造器
例子
匿名內部類能做的,方法內部類都能做。如果物件只會建立一次,而且不需要構造方法來接受引數,則可以使用匿名內部類。
在呼叫方法時,很多方法都需要一個介面引數,如果Arrays.sort方法,它可以接收以一個數組以及一個Comparator介面引數,
Comparator有一個方法compare用於比較兩個物件,比如,要對一個字串陣列不區分大小寫排序,可以使用Arrays.sort
public void sortIgnoreCase(String[] strs){
Arrays.sort(strs, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
}