a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 272|回复: 4

[专业语言] JAVA认证:java的内部类与匿名内部类

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
java的内部类与匿名内部类: Q( u) J& @# E8 ~+ P! j; |
public interface Contents {8 ^* ^- L" m9 ^$ i
int value();
, j- |9 T, x) Z5 K}
. Q1 [  c* C( X& r! ypublic interface Destination {
% g/ x2 A) u$ t, a) q8 yString readLabel();0 p) x) R; a; z3 Q* g& Y* Q) d
}
% I% @( h0 R# Hpublic class Goods {
6 b' A& n# W$ ?* mprivate class Content implements Contents {
3 O. H9 U% s+ bprivate int i = 11;5 l- I% w( |$ t' r+ \1 [
public int value() {
5 V* m6 T) W9 R) X2 z; @7 v! nreturn i;
7 v# r7 I7 l. P+ C}
' |+ q$ I* {. L/ E" L}/ H0 w# K9 `9 g0 D7 ?4 \
protected class GDestination implements Destination {
  F3 s. A( I# z; @* Rprivate String label;
: Q3 K* ~. A' y% S& {' Xprivate GDestination(String whereTo) {/ e1 g  T: h! K" }# ~
label = whereTo;
/ D  w  {; `% F4 f}
. X0 |" d1 @5 o+ _public String readLabel() {7 I% R1 h# e2 A
return label;: k5 w6 O0 T$ ^5 t
}4 E; f5 A9 r7 j7 Y
}
% f% m+ h/ L# fpublic Destination dest(String s) {
; K( F, [# [$ m; _return new GDestination(s);% @" E$ w# s2 t
}
8 _0 ^. O1 L0 p9 ~public Contents cont() {* J6 z* t/ G- _' {( Y# ~
return new Content();
: J' e* i2 I' {0 f9 B; D}
& H; _. X4 a5 d- p}) r* ?& x) A. H* _8 H. V
class TestGoods {. D8 ^: s  y1 Y$ P
public static void main(String[] args) {
- z( Q3 J2 g0 j; s1 Z$ z0 J- PGoods p = new Goods();
  w8 Z0 w! \& l! W; HContents c = p.cont();
8 ?& V( A2 J9 r  u6 w7 ADestination d = p.dest(“Beijing”);
7 r3 G4 H- B( z$ X7 K" H, i0 C}
& y# {" _$ g& B* I7 I, Y! K* v4 D7 q* Y, M9 O- D" N( h
}
回复

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:45 | 显示全部楼层

JAVA认证:java的内部类与匿名内部类

</p>在这个例子里类Content和GDestination被界耸ё仝了类Goods内部,而且分袂有着protected和private润色符来节制访谒级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分袂实现了两个接口Content和Destination。在后面的main体例里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个益处就浮现出来了——潜匿你不想让别人知道的操作,也即封装性。
1 \  J- O! t3 y" V同时,我们也发现了在外部类浸染规模之外获得内部类对象的第一个体例,那就是操作其外部类的体例建树并返回。上例中的cont()和dest()体例就是这么做的。那么还有没有此外体例呢?当然有,其语法名目如下:
/ R8 M. ^$ o2 {outerObject=new outerClass(Constructor Parameters);
: J5 A1 D  x2 @( n* A" I! k1 ]outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
0 P' X+ j# C& t! Q- G. w, Q  y注重在建树风止态内部类对象时,必然要先建树起响应的外部类对象。至于原因,也就引出了我们下矣闽话题——0 T$ Q' u- ?: _
风止态内部类对象有着指向其外部类对象的引用
: B9 P* p6 o' b) t& L9 ?1 B7 v对适才的例子稍作改削:$ Y3 P. o6 R  ^: A+ U& M$ g& w
public class Goods {- V7 t1 ^) c" O3 N) g
private valueRate=2;
- B0 b- E9 w! Iprivate class Content implements Contents {8 A7 L6 f6 i& _2 W! {
private int i = 11*valueRate;
" q- }0 h1 Y0 b( dpublic int value() {
( C' w4 v  ]6 d2 I/ U2 P  D: yreturn i;$ k8 K( u0 {% ~, t0 }6 r7 o
}
7 k* M6 j' @5 o# e8 T' c}
& p- ~5 D, Z3 {/ I3 ~1 `! N( Q5 n& `6 P" X' E6 [
protected class GDestination implements Destination {
1 ~8 [  w4 s/ |8 X# M- d0 V/ W7 ~private String label;1 ^' Y" J5 Q0 r5 O2 b% I+ P
private GDestination(String whereTo) {* r( U, F+ `: q
label = whereTo;( m) k0 w  p9 L' X4 O- q4 M
}* H2 z5 }2 ~$ X% ]' |1 v
public String readLabel() {4 Q7 {8 t0 o$ g& o% |) N2 n
return label;
* m  i& A  F( a6 g4 f}7 Y6 B) C4 w$ K
}
! J8 l) r  ~: {! x2 g( Hpublic Destination dest(String s) {$ i1 @0 I* `! A7 L7 X2 ]; ~+ Z
return new GDestination(s);
; o( Y5 C" _4 y+ t. H}
2 w2 \, D) q  z* j7 u0 tpublic Contents cont() {$ Y  ?% w7 e/ N- T( ~! z
return new Content();
# L* Q" y: S4 ~4 o}
' M: b* X8 r1 a' g6 z}0 }& l( r2 v: {4 Z& c
改削的部门用蓝色显示了。在这里我们给Goods类增添了一个private成员变量valueRate,意义是货色的价值系数,在内部类Content的体例value()计较价值时把它乘上。我们发现,value()可以访谒valueRate,这也是内部类的第二个益处——一个内部类对象可以访谒建树它的外部类对象的内容,甚至搜罗私有变量!这是一个很是有用的特征,为我们在设计时供给了更多的思绪和捷径。要想实现这个功能,内部类对象就必需有指向外部类对象的引用。Java编译器在建树内部类对象时,隐式的把其外部类对象的引用也传了进去并一向保留着。这样就使得内部类对象始终可以访谒其外部类对象,同时这也是为什么在外部类浸染规模之外向要建树内部类对象必需先建树其外部类对象的原因。, @6 v5 ^0 [$ {; W
有人会问,如不美观内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏障了,怎么办?没事,Java里用如下名目表达外部类的引用:! t2 t0 c" |* z! a- u
outerClass.this& J+ I2 Q$ Z- b$ |5 b
有了它,我们就不怕这种屏障的情形了。
. e- U# N6 u0 T8 C1 Z静态内部类2 g& X5 T( g" ]+ k
和通俗的类一样,内部类也可以有静态的。不外和风止态内部类对比,区别就在于静态内部类没有了指向外部的引用。这现实上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的分歧就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。1 t5 X: b* E# v! T$ h
除此之外,在任何风止态内部类中,都不能有静态数据,静态体例或者又一个静态内部类(内部类的嵌套可以不止一层)。不外静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。' i0 _+ {+ I7 q" |4 e- i
局部内部类" a6 D' K- X' D3 f) w# U" G
是的,Java内部类也可所以局部的,它可以界耸ё仝一个体例甚至一个代码块之内。+ F( f! y- s: p& x, t. O3 h' @
public class Goods1 {
2 x' Z1 e( M" Q& ?+ ~- C  V6 Fpublic Destination dest(String s) {1 w( n0 |  @5 U4 K/ ?# @6 ~1 ?4 q
class GDestination implements Destination {
; u( p% }7 e  P- t! \1 \' ]private String label;) v2 x5 B  y" G7 O" m. f5 ~7 b
private GDestination(String whereTo) {9 x0 r* h/ m3 O1 O! U
label = whereTo;
" G* L* k0 ?5 V4 G7 N}
9 k" [2 ]7 F! a! gpublic String readLabel() { return label; }9 @' {; |) l8 ^7 N7 a8 {
}
. d* \% i, G- F3 Z! r( Y& Yreturn new GDestination(s);# y( y8 g" B4 I& U; C; Z% a& K
}
9 y6 A7 \; f# ~! L4 j# epublic static void main(String[] args) {3 z4 V! S# A+ j; d
Goods1 g= new Goods1();" b0 t. J* x+ X* v
Destination d = g.dest(“Beijing”);- p" w9 N1 B9 ]8 P3 E- R: |
}
" E  `( t4 }) }# w! `/ w}8 M# p# Q( J4 ~; N' ]+ B1 X
膳缦沔就是这样一个例子。在体例dest中我们界说了一个内部类,最后由这个体例返回这个内部类的对象。如不美观我们在用一个内部类的时辰仅需要建树它的一个对象并创给外部,就可以这样做。当然,界耸ё仝体例中的内部类可以使设计多样化,用途毫不仅仅在这一点。3 H# L" w7 u% P/ O4 E& M1 q/ n) }
下面有一个更怪的例子:9 r- M; S" ^; t) Y2 @
public class Goods2{5 G) ^( P+ X5 r
private void internalTracking(boolean b) {
1 I7 z: I6 E# F) D; E8 V+ ~9 v/ qif(b) {
8 I* J) }" H- p6 k( nclass TrackingSlip {+ b; F/ d6 I  c
private String id;
+ L8 G# i% E) e# ?. C) ^TrackingSlip(String s) {
9 p2 A& g2 v/ ?- \! b$ Lid = s;& J& S) `. |. ~7 Q2 N# @" I! c/ S
}
# o6 T, R0 S" x, R$ `; C8 @String getSlip() { return id; }4 d$ B: @1 I* V6 [* y9 |, \- w
}  \1 K3 _: Y( ]7 z1 n
TrackingSlip ts = new TrackingSlip(“slip”);/ b4 J5 O2 {- `: ]
String s = ts.getSlip();4 @$ Q: |* E. H
# ^% N8 B8 v4 o* E4 n$ k, c
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:46 | 显示全部楼层

JAVA认证:java的内部类与匿名内部类

</p>}8 [$ @- s/ T: W9 x# `; ~
public void track() { internalTracking(true); }7 i! {8 e, Y" O3 e- Z3 C. G
public static void main(String[] args) {( ^  G5 }" j$ Y' R& R+ i: X
Goods2 g= new Goods2();
$ e6 a3 J9 W: ^4 E' Fg.track();) V& A9 v- Z! |
}$ c& y# f4 Z% i
}: Y$ E" o$ ?' U' Y5 p# t6 m9 c
你不能在if之外建树这个内部类的对象,因为这已经超出了它的浸染域。不外在编译的时辰,内部类TrackingSlip和其他类一样同时被编译,只不外它由它自己的浸染域,超出了这个规模就无效,除此之外它和其他内部类并没有区别。
% g! z7 J$ W( }5 ?: l& p- o+ |# a& r. x匿名内部类) n$ w; k3 u+ w9 Z
java的匿名内部类的语犯罪则看上去有些怪僻,不外如同匿名数组一样,当你只需要建树一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去精练清嚣张。它的语犯罪则是这样的:5 Q1 r+ ^  L  l) N/ ^; [  o8 e
// 有点js中 return function(){。..。..};的意思
: P# [3 j/ g* r" x6 u6 d1 y" Inew interfacename(){。..。..}; 或 new superclassname(){。..。..};  q; r5 ^$ V8 ^* S4 }
// 接口的名字或者父类的名字
9 F- I1 `  x4 a. n8 `- U5 [) i3 ]下面接着前面继续举例子:
" \* Y1 y8 h. q8 y, }1 `5 spublic class Goods3 {) W0 ^9 x3 y& y; ~; f- n
public Contents cont(){
( D; Q% d+ j* r  |& Rreturn new Contents(){& y! X. y. w# [/ a( C
private int i = 11;
1 w6 `; D9 H2 J, O* Jpublic int value() {9 x$ a  e( x) n
return i;
, I1 j4 l# Q2 n5 r" S}
7 Q1 U& Y2 D- y5 {0 \, x0 |3 H};
9 {4 u9 u' E" \/ M/ [}
; G7 Y9 f6 }. e) {6 ]}
* k. ~; S+ o; |8 ]+ m$ k1 j4 h这里体例cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去简直十分炊洁。, {. M6 k: H- {1 s
在java的事务措置的匿名适配器中,匿名内部类被大量的使用。例如在想封锁窗口时加上这样一句代码:
- f2 y& |+ J9 n2 P3 w5 d9 R4 f, }frame.addWindowListener(new WindowAdapter(){. T8 G; G/ H8 _4 ~' A$ ?3 K* N1 L/ q- T
public void windowClosing(WindowEvent e){% v3 o7 j; D6 H
System.exit(0);
; c3 \  e6 [: A6 O}
; ]9 U: I1 T6 \' \3 y6 r5 M});# A: s: i: X5 J$ `/ J
有一点需要注重的是,匿名内部类因为没有名字,所以它没有机关函数(可是如不美观这个匿名内部类担任了一个只含有带参数机关函数的父类,建树它的时辰必需带上这些参数,并在实现的过程中使用super关头字挪用响应的内容)。如不美观你想要初始化它的成员变量,有下面几种体例:
! f) _& O/ P& F- j如不美观是在一个体例的匿名内部类,可以操作这个体例传进你想要的参数,不外记住,这些参数必需被声明为final。
- U8 P9 \. K0 \8 @将匿名内部类刷新成有名字的局部内部类,这样它就可以拥有机关函数了。
$ ^" H: W0 J7 e: k! {在这个匿名内部类中使用初始化代码块。
" w) R% E6 T6 Y, i! u为什么需要内部类?: f7 U9 K: x. a
java内部类有什么益处?为什么需要内部类?
' _/ P3 r& u! n7 w6 k7 D首先举一个简单的例子,如不美观你想实现一个接口,可是这个接口中的一个体例和你构想的这个类中的一个体例的名称,参数不异,你应该怎么办?这时辰,你可以建一个内部类实现这个接口。因为内部类对外部类的所有内容都是可访谒的,所以这样做可以完成所有你直接实现这个接口的功能。" x( [2 y4 P- a" l& B
不外你可能要质疑,更改一下体例的不就行了吗?
- l9 c2 b9 ~. g7 F$ p简直,以此作为设计内部类的理由,其实没有说服力。7 s; E4 l/ W$ ?
真正的原因是这样的,java中的内部类和接口加在一路,可以的解决常被C++轨范员埋怨java中存在的一个问题——没有多担任。现实上,C++的多担任设计起来很复杂,而java经由过程内部类加上接口,可以很好的实现多担任的效不美观。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:47 | 显示全部楼层

JAVA认证:java的内部类与匿名内部类

</p>6 D% b6 i5 Z' u* E7 `
' U! {+ O1 ~' I5 v  }0 K2 \
若何优化?& r& o/ C0 n, `" ]6 ?
知道了在那儿那里优化,但若何进行优化呢?我们知道大部门的运算时刻被花在了绘图函数上,J2ME已经为我们供给了这些函数,我们没有法子对这些函数的内部进行优化,可是我们仍然有选择权。下面我们来对J2ME供给给我们的绘图函数作一测试。8 K: z) X5 h2 b( C- a7 h
在Canvas类里添加测试代码如下:
& G; H" i+ x3 ~2 {# k: yprotected void paint(Graphics g) {) E0 D5 k+ R) [  s
TestPaint(g);$ d7 a0 F% T! A4 @. P
}
% G- g+ \2 D9 U  j4 D& \& k9 i1 Ivoid TestPaint(Graphics g) {
9 h! I* P, L" A. p1 G' g0 hsetClip(g);
0 E' y1 V; w9 H$ o! u% ^- o) n. H* TsetColor(g);
, m0 D6 U- B+ _8 p; Km_font = getFont();( A- O# y1 Z* B2 Y+ O) h* v
setFont(g);
, `, Q/ Y9 P7 G$ n/ y. t. v5 zdrawString(g);* |$ m) C" _- L- j& B( l0 q% P
drawRect(g);) H, ?9 @  s/ R+ B
fillRect(g);! e: F; u, R4 S4 S
drawImage(g);& g" ^* I7 W& F2 ~
drawRegion(g);0 o; {" n: {5 f: `2 I, w
drawArc(g);- J2 b% A9 L) G8 S3 M, h
drawChar(g);
. u8 h& n$ f  H2 q: @# I& V) tdrawLine(g);4 ~3 `8 o/ |# R* t1 N$ Z" N* Z
drawRoundRect(g);2 L( s) o; h( u% @" O
fillArc(g);) q: \: s! d5 P' b) [5 M/ P, g
fillRoundRect(g);
# A) {9 V0 \  p3 }6 z8 L}' ~& v0 _6 Y1 \4 q* o, E" X- q+ q
void setColor(Graphics g) {5 P6 Y% \& o0 w: M0 g0 A- R
g.setColor(0);
6 w- y. @2 U' E}
( k6 g  }: k$ ]& b* Kvoid drawArc(Graphics g) {
! @$ @, T4 b# [0 |( o3 Mg.drawArc(0, 0, 100, 100, 4, 4);+ g1 H' X) o* s& O& G  d5 c- X
}6 ?$ E0 J7 C1 Y
void drawChar(Graphics g) {
2 s+ }* q. T/ W4 k8 V; sg.drawChar(‘你’, 0, 0, GE.TOPLEFT);
- c( ]+ u- `" y3 T4 K) S}
6 \' s8 e* _$ C* J- ]void drawRoundRect(Graphics g) {
* C( ~4 E, a- n  e+ i) bg.drawRoundRect(0, 0, 100, 100, 4, 4);
: N; G+ \6 c) g  L! f}
- E# ]1 u  }5 l& t$ N' {1 ~void fillRoundRect(Graphics g) {
5 [8 K6 Z' t' a1 Tg.fillRoundRect(0, 0, 100, 100, 4, 4);
  n( ?1 b8 u, ~}
, B3 Q! N0 A5 b: F( n. t5 D# [void fillArc(Graphics g) {+ u) L6 o. ~' u5 \
g.fillArc(0, 0, 100, 100, 4, 4);9 T9 D$ F( p- Q
}% n: l" a0 x- u: q0 ~  Z
void drawLine(Graphics g) {
' F" Z, ?" A$ _# Q+ }% W7 G' C; Yg.drawLine(0, 0, 100, 100);. b! {6 ^5 z1 o& Q. y- a. v) V
}
- W* ?' }/ {5 @- pFont getFont() {
" b6 G+ x2 [& `0 l; jreturn Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
! m0 B4 W9 A+ @}- k; X' M7 \/ E* U
: }/ v. ]3 B4 G; S1 E- h

9 V' ^$ J  P4 T; C3 O9 E. ]" @void setFont(Graphics g) {& E; v: a: b* T+ n7 L. W8 i
g.setFont(m_font);! H& }; H; Y5 s. m( k$ r6 P% G
}
; v3 k, M( l7 R  Q! U& l& r# @void drawString(Graphics g) {
& X( h# H  c1 }; V# zg.drawString(“你好”, 0, 0, GE.TOPLEFT);6 o5 ^; p0 \5 ?6 m& z3 E3 m
}
0 l5 Q  Q; u' {" B! O. x4 }void drawRect(Graphics g) {
# {8 y% H$ S0 k* @+ Rg.drawRect(0, 0, 100, 100);3 h# w/ N3 a0 g$ e  N8 _! \/ N
}7 J$ E. s% @' g* h5 d1 h: W
void setClip(Graphics g) {
, L) Z: I! `9 Z  h8 F* yg.setClip(0, 0, 300, 300);
5 R9 ]1 w# F- g4 D}* ^6 a: ~& V- X3 o
void fillRect(Graphics g) {1 P1 w3 O6 b) Q: y0 u
g.fillRect(100, 0, 100, 100);3 V6 ~: O9 m0 k- r" O) g! ~. x4 y
}' A' ?! i8 S2 e1 `- Z4 H
void drawImage(Graphics g) {
7 p* F# M8 P3 n% D0 gg.drawImage(GE.m_images[GRes.PNG_MAP], 0, 100, GE.TOPLEFT);2 i6 D. q# M0 p  Y
}" h8 A5 d- S# c" {( W& W
void drawRegion(Graphics g) {' x. h# l4 w: F8 R& n1 K3 w! B4 y
g.drawRegion(GE.m_images[GRes.PNG_MAP], 0, 0, 100, 100, Sprite.TRANS_MIRROR,100, 100, GE.TOPLEFT);
7 n# w1 ?4 B3 ?/ [; Q, R$ i, J& }5 h' S3 }0 d+ i
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:48 | 显示全部楼层

JAVA认证:java的内部类与匿名内部类

</p>该轨范各函数分袂绘制100*100的图形,经由一段侍旧笋后,退出应用轨范5 `- P0 Y7 ]/ [# T  l
按照Profiler窗口所显示的数据,我们发现drawString最耗时。其次是drawRegion,所以我们应尽量避免使用drawString函数。8 p* z  D) e4 T& e1 i  p
经由过程Profiler对各类函数及轨范的测试,我总结如下结论:7 y5 j6 Q5 c" v! G3 X( V+ k
◆仅当你需要的时辰才去优化代码!+ ~3 M$ d" n" P( C" x6 @& o) O
◆仅优化那些最耗时的代码!
1 b$ d  b/ u8 f7 |( U◆使用Profiler去查找哪里需要优化!  r: Y0 j9 q7 y' M
◆记住Profiler不代表真机上的优化结不美观,使用System Timer来在真机上做最后的测试!9 O( |8 P' d& R% z9 i1 L  @4 \
◆在做初级优化之前,老是要先思虑算法是否是最优!
9 O! X( |+ J/ H. `0 R3 G' @( U8 n* g. f◆绘图是很占用时刻的,所以尽可能的削减Graphics函数的挪用!
! W  S/ z" c4 D% L5 O◆尽可能的使用SetClip()来削减绘图区域,相对于SetClip(),drawImage()所花的时刻会更可不美观!; ~4 P" M8 o! i9 ~
◆尽可能的将变量界耸ё仝轮回以外!
, T' |+ L. r" B◆尽最大可能的进行对需要的数据进行预先计较并将结不美观保留在缓冲里!6 X0 F  W% n. L3 Q7 s" a9 P
◆String类很轻易发生垃圾内存,尽可能的使用StringBuffer庖代String或用final static来界说之!7 X: h/ |! ]6 d3 `
◆假设是不被接管的,一切要以真机为据!
$ @+ r* E7 ~3 h- B5 f$ ^. {◆尽量使用static final润色函数,而避免synchronized润色符!" l( l  e) n& r0 B8 {
◆对于频仍挪用的函数要使用尽可能少的参数!
+ V% e, q6 \# t4 V! f, n◆尽可能的不使用函数挪用!
6 U( o5 N  {0 ~- u. i# X3 b. i◆尽可能的使用《《和》》来庖代*和/!
4 n# B# r4 Z" h5 _/ O% c◆使用位操作来庖代%运算!$ t% C0 v9 I8 V: O: L/ |
◆与0斗劲比与其他数值斗劲快!- I1 Z! U9 E  a! Y& b
◆数组存取比C说话慢,尽可能不在轮回中存取数组!
0 N, d6 n4 w, i  G: n◆局部变量比其他类型的变量运算要快!
* W' Y8 {: X, K% A' {& y: K/ V% I. j◆在switch()中尽量使用持续的小数值判定
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-8 06:01 , Processed in 0.189243 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表