JSP指令标签起名、动作标签

Java内部类详解

 

Java内部类详解

  说起内部类那么些词,想必很三个人都不素不相识,但是又会觉得不熟谙。原因是平时编辑代码时大概用到的现象不多,用得最多的是在有事件监听的事态下,并且即利用到也很少去下结论内部类的用法。明天我们就来一探究竟。下边是本文的目录大纲:

  一.内类型基础

  二.尖锐掌握里面类

  三.内项指标使用意况和好处

  四.科学普及的与中间类相关的笔试面试题

  若有不正之处,请多担待并欢迎批评指正。

  请珍视笔者劳动成果,转发请标明原来的书文链接:

  http://www.cnblogs.com/dolphin0520/p/3811445.html

JSP有三大指令:

一.内项目基础

  在Java中,能够将贰个类定义在另贰个类里面只怕3个方法里面,那样的类称为个中类。广泛意义上的中间类一般的话包含那多样:成员内部类、局地内部类、匿名内部类和静态内部类。上边就先来打探一下那二种内部类的用法。

  1.成员内部类

  成员内部类是最平凡的内部类,它的定义为放在另叁个类的中间,形如上边包车型地铁花样:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Circle {
    double radius = 0;
     
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println("drawshape");
        }
    }
}

  那样看起来,类Draw像是类Circle的二个分子,Circle称为外部类。成员内部类能够无条件访问外部类的全部成员属性和分子方法(包涵private成员和静态成员)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);   //外部类的静态成员
        }
    }
}

  不过要小心的是,当成员内部类具有和外部类同名的成员变量恐怕措施时,会发生隐藏现象,即暗许情状下访问的是成员内部类的成员。假诺要访问外部类的同名成员,须要以下边的样式展开走访:

1
2
外部类.this.成员变量
外部类.this.成员方法

  就算成员内部类能够无偿地拜会外部类的分子,而外部类想访问成员内部类的成员却不是那般随便了。在外表类中假如要拜访成员内部类的成员,必须先创造一个分子内部类的目的,再通过指向那些目的的引用来拜访:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Circle {
    private double radius = 0;
 
    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问
    }
     
    private Draw getDrawInstance() {
        return new Draw();
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
        }
    }
}

  成员内部类是隶属外部类而留存的,也正是说,假设要开创成员内部类的目的,前提是必须存在3个外部类的对象。创设成员内部类对象的貌似方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Test {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建
         
        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
 
class Outter {
    private Inner inner = null;
    public Outter() {
         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    class Inner {
        public Inner() {
             
        }
    }
}

  内部类能够拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上边的例证,若是成员内部类Inner用private修饰,则不得不在外部类的中间访问,假如用public修饰,则别的地点都能访问;如若用protected修饰,则不得不在同贰个包下只怕三番五次外部类的情事下访问;如果是默许访问权限,则只幸好同二个包下访问。这或多或少和外部类有一些差别,外部类只好被public和包访问三种权限修饰。作者个人是如此领会的,由于成员内部类看起来像是外项目标2个成员,所以可以像类的分子平等具有三种权力修饰。

  2.有个别内部类

  局地内部类是概念在二个艺术照旧一个成效域里面包车型客车类,它和成员内部类的区分在于有的内部类的造访仅限于方法内可能该功效域内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class People{
    public People() {
         
    }
}
 
class Man{
    public Man(){
         
    }
     
    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

  注意,局地内部类就好像方法里面包车型地铁四个片段变量一样,是不能够有public、protected、private以及static修饰符的。

  3.匿名内部类

  匿名内部类应该是日常大家编辑代码时用得最多的,在编辑事件监听的代码时选用匿名内部类不但有利,而且使代码特别便于保证。下边那段代码是一段Android事件监听代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scan_bt.setOnClickListener(new OnClickListener() {
             
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 
            }
        });
         
        history_bt.setOnClickListener(new OnClickListener() {
             
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 
            }
        });

  这段代码为七个按钮设置监听器,那中间就利用了匿名内部类。那段代码中的:

1
2
3
4
5
6
7
8
new OnClickListener() {
             
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 
            }
        }

  正是匿名内部类的应用。代码中必要给按钮设置监听器对象,使用匿名内部类能够在促成父类也许接口中的方法情状下同时产生一个应和的靶子,可是前提是以此父类大概接口必须先存在才能这么使用。当然像上面那种写法也是足以的,跟上边使用匿名内部类达到效果一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void setListener()
{
    scan_bt.setOnClickListener(new Listener1());       
    history_bt.setOnClickListener(new Listener2());
}
 
class Listener1 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
             
    }
}
 
class Listener2 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
             
    }
}

  这种写法即使能完毕平等的功效,然而既冗长又难以启齿维护,所以一般选取匿名内部类的措施来编排事件监听代码。同样的,匿名内部类也是无法有访问修饰符和static修饰符的。

  匿名内部类是唯一一种没有构造器的类。正因为其尚无构造器,所以匿名内部类的使用限制13分不难,抢先四分之二匿名内部类用于接口回调。匿名内部类在编写翻译的时候由系统活动起名为Outter$1.class。一般的话,匿名内部类用于后续其余类大概达成接口,并不必要扩张额外的法门,只是对接二连三方法的兑现或是重写。

  4.静态内部类

  静态内部类也是概念在另三个类里面包车型客车类,只可是在类的先头多了2个至关心珍视要字static。静态内部类是不须求借助于外部类的,那一点和类的静态成员属性有点类似,并且它无法应用外部类的非static成员变量恐怕措施,那一点很好明白,因为在未曾外部类的目的的情状下,能够创立静态内部类的对象,假使允许访问外部类的非static成员就会发生争论,因为外部类的非static成员必须依附于实际的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}
 
class Outter {
    public Outter() {
         
    }
     
    static class Inner {
        public Inner() {
             
        }
    }
}

  起名 1

  * page指令
  * include指令
  * taglib指令
 
 在JSP中没有其它命令是必须的!!!

二.尖锐领悟个中类

  1.怎么成员内部类能够无条件访问外部类的分子?

  之前,大家曾经研究过了成员内部类能够无偿访问外部类的积极分子,那现实毕竟是怎样贯彻的呢?下边通过反编写翻译字节码文件看看终究。事实上,编译器在实行编写翻译的时候,会将成员内部类单独编写翻译成一个字节码文件,上面是Outter.java的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Outter {
    private Inner inner = null;
    public Outter() {
         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    protected class Inner {
        public Inner() {
             
        }
    }
}

  编写翻译之后,现身了三个字节码文件:

起名 2

  反编写翻译Outter$Inner.class文件得到下边音信:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
E:\Workspace\Test\bin\com\cxh\test2>javap -v Outter$Inner
Compiled from "Outter.java"
public class com.cxh.test2.Outter$Inner extends java.lang.Object
  SourceFile: "Outter.java"
  InnerClass:
   #24= #1 of #22//Inner=class com/cxh/test2/Outter$Inner of class com/cxh/tes
t2/Outter
  minor version: 0
  major version: 50
  Constant pool:
const #1 class        #2;     //  com/cxh/test2/Outter$Inner
const #2 = Asciz        com/cxh/test2/Outter$Inner;
const #3 class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        this$0;
const #6 = Asciz        Lcom/cxh/test2/Outter;;
const #7 = Asciz        <init>;
const #8 = Asciz        (Lcom/cxh/test2/Outter;)V;
const #9 = Asciz        Code;
const #10 = Field       #1.#11//  com/cxh/test2/Outter$Inner.this$0:Lcom/cxh/t
est2/Outter;
const #11 = NameAndType #5:#6;//  this$0:Lcom/cxh/test2/Outter;
const #12 = Method      #3.#13//  java/lang/Object."<init>":()V
const #13 = NameAndType #7:#14;//  "<init>":()V
const #14 = Asciz       ()V;
const #15 = Asciz       LineNumberTable;
const #16 = Asciz       LocalVariableTable;
const #17 = Asciz       this;
const #18 = Asciz       Lcom/cxh/test2/Outter$Inner;;
const #19 = Asciz       SourceFile;
const #20 = Asciz       Outter.java;
const #21 = Asciz       InnerClasses;
const #22 class       #23;    //  com/cxh/test2/Outter
const #23 = Asciz       com/cxh/test2/Outter;
const #24 = Asciz       Inner;
 
{
final com.cxh.test2.Outter this$0;
 
public com.cxh.test2.Outter$Inner(com.cxh.test2.Outter);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:   aload_0
   1:   aload_1
   2:   putfield        #10//Field this$0:Lcom/cxh/test2/Outter;
   5:   aload_0
   6:   invokespecial   #12//Method java/lang/Object."<init>":()V
   9:   return
  LineNumberTable:
   line 160
   line 189
 
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      10      0    this       Lcom/cxh/test2/Outter$Inner;
 
 
}

  第贰1行到35行是常量池的始末,上边逐一第28行的内容:

final com.cxh.test2.Outter this$0;

  那行是一个针对性外部类对象的指针,看到那里恐怕我们豁然开朗了。也正是说编写翻译器会暗中同意为成员内部类添加了叁个针对性外部类对象的引用,那么这些引用是哪些赋初值的吗?上面接着看里面类的构造器:

public com.cxh.test2.Outter$Inner(com.cxh.test2.Outter);

  从这边能够看看,即便大家在概念的内部类的构造器是无参构造器,编写翻译器依旧会暗中认可添加一个参数,该参数的品类为指向外部类对象的2个引用,所以成员内部类中的Outter
this&0
指针便指向了表面类对象,由此得以在成员内部类中随心所欲走访外部类的分子。从此处也直接表明了成员内部类是依靠于表面类的,若是没有创造外部类的靶子,则不能对Outter
this&0引用举办开首化赋值,也就不恐怕创造成员内部类的目的了。

  2.为啥有的内部类和匿名内部类只可以访问片段final变量?

  想必那个难题也一度烦扰过许四人,在谈论那些题材在此以前,先看上面那段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test {
    public static void main(String[] args)  {
         
    }
     
    public void test(final int b) {
        final int a = 10;
        new Thread(){
            public void run() {
                System.out.println(a);
                System.out.println(b);
            };
        }.start();
    }
}

  那段代码会被编写翻译成七个class文件:Test.class和Test1.class。暗中同意情况下,编写翻译器会为匿名内部类和一部分内部类起名为Outter1.class。暗中认可景况下,编写翻译器会为匿名内部类和部分内部类起名为Outterx.class(x为正整数)。

  起名 3

  遵照上海教室可以,test方法中的匿名内部类的名字被起为 Test$1。

  上段代码中,若是把变量a和b前边的任多个final去掉,那段代码都编写翻译但是。大家先考虑那样1个题材:

  当test方法执行达成之后,变量a的生命周期就终止了,而此刻Thread对象的生命周期很可能还没有终结,那么在Thread的run方法中持续访问变量a就改成不容许了,可是又要兑现如此的功效,如何是好呢?Java选择了 复制 
的伎俩来缓解这些题材。将那段代码的字节码反编译能够拿走上面包车型大巴情节:

起名 4

  大家见到在run方法中有一条指令:

bipush 10

  那条指令表示将操作数10压栈,表示使用的是三个地点局地变量。那个进程是在编写翻译期间由编写翻译器暗中认可举行,假若那个变量的值在编写翻译时期能够规定,则编写翻译器暗中同意会在匿名内部类(局地内部类)的常量池中添加2个内容非常的字面量或直接将相应的字节码嵌入到实施字节码中。那样一来,匿名内部类应用的变量是另一个有的变量,只可是值和方法中一些变量的值卓绝,因而和章程中的局地变量完全部独用立开。

  上面再看多个例证:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test {
    public static void main(String[] args)  {
         
    }
     
    public void test(final int a) {
        new Thread(){
            public void run() {
                System.out.println(a);
            };
        }.start();
    }
}

  反编写翻译获得:

起名 5

  大家看出匿名内部类Test$1的构造器含有多个参数,3个是指向外部类对象的引用,2个是int型变量,很驾驭,那里是将变量test方法中的形参a以参数的形式传进来对匿名内部类中的拷贝(变量a的正片)进行赋值早先化。

  也就说假设有个别变量的值在编写翻译时期就能够规定,则平素在匿名内部里面创立3个拷贝。如若部分变量的值不能在编写翻译时期分明,则经过构造器传参的办法来对拷贝实行伊始化赋值。

  从地点可以见见,在run方法中走访的变量a根本就不是test方法中的局地变量a。那样一来就化解了前头所说的
生命周期不雷同的标题。可是新的难题又来了,既然在run方法中访问的变量a和test方法中的变量a不是同3个变量,当在run方法中改变变量a的值的话,会现出什么意况?

  对,会招致数据分化性,那样就达不到原来的打算和须要。为了化解这些标题,java编写翻译器就限制必须将变量a限制为final变量,不相同意对变量a举办转移(对于引用类型的变量,是不容许指向新的指标),那样数据分歧性的难点就足以消除了。

  到那边,想必我们应该理解为啥方法中的局地变量和形参都无法不用final实行限定了。

  3.静态内部类有特殊的地点吗?

  在此此前方能够清楚,静态内部类是不借助于外部类的,也就说能够在不创建国门外部类对象的意况下成立内部类的对象。其余,静态内部类是不富有指向外部类对象的引用的,这几个读者能够友善尝尝反编写翻译class文件看一下就精通了,是向来不Outter
this&0引用的。

 
 但基本上各类JSP都以运用page指令! 

三.内部类的行使境况和好处

  为何在Java中必要中间类?总括一下要害有以下四点:

  1.各类内部类都能独立的接续1个接口的完结,所以无论外部类是不是曾经再而三了有个别(接口的)完结,对于个中类都不曾影响。内部类使得多一而再的缓解方案变得完全,

  2.有利于将设有一定逻辑关系的类组织在一齐,又有啥不可对外场隐藏。

  3.惠及编写事件驱动程序

  4.福利编写线程代码

  个人认为第③点是最要害的来由之一,内部类的留存使得Java的多继承机制变得越来越周详。

四.科学普及的与当中类相关的笔试面试题

 1.遵照注释填写(1),(2),(3)处的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Test{
    public static void main(String[] args){
           // 初始化Bean1
           (1)
           bean1.I++;
           // 初始化Bean2
           (2)
           bean2.J++;
           //初始化Bean3
           (3)
           bean3.k++;
    }
    class Bean1{
           public int I = 0;
    }
 
    static class Bean2{
           public int J = 0;
    }
}
 
class Bean{
    class Bean3{
           public int k = 0;
    }
}

  在此以前边可见,对于成员内部类,必须头阵生外部类的实例化对象,才能发出内部类的实例化对象。而静态内部类不用产生外部类的实例化对象即可产生内部类的实例化对象。

  创造静态内部类对象的一般方式为:  外部类类名.内部类类名 xxx = new
外部类类名.内部类类名()

  创设成员内部类对象的形似格局为:  外部类类名.内部类类名 xxx =
外部类对象名.new 内部类类名()

  由此,(1),(2),(3)处的代码分别为:

起名 6 View Code

 

起名 7 View Code

 

起名 8 View Code

2.上边那段代码的出口结果是如何?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test {
    public static void main(String[] args)  {
        Outter outter = new Outter();
        outter.new Inner().print();
    }
}
 
 
class Outter
{
    private int a = 1;
    class Inner {
        private int a = 2;
        public void print() {
            int a = 3;
            System.out.println("局部变量:" + a);
            System.out.println("内部类变量:" this.a);
            System.out.println("外部类变量:" + Outter.this.a);
        }
    }
}

起名 9 View Code

 

  最终补充有些学问:关于成员内部类的持续难点。一般的话,内部类是很少用来作为接二连三用的。可是当用来接二连三的话,要小心两点:

  1)成员内部类的引用方式必须为 Outter.Inner.

  2)构造器中必须有指向外部类对象的引用,并经过这一个引用调用super()。那段代码摘自《Java编制程序思想》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class WithInner {
    class Inner{
         
    }
}
class InheritInner extends WithInner.Inner {
      
    // InheritInner() 是不能通过编译的,一定要加上形参
    InheritInner(WithInner wi) {
        wi.super(); //必须有这句调用
    }
  
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner obj = new InheritInner(wi);
    }
}

page指令

page指令是无限常用的指令!

  1. page指令的常用属性:

* import:等同与import语句

  –> <%@ page
import=”Java.util.*” %>

  –> <%@ page
import=”java.util.*, java.NET.*”
%>

  –>
在三个JSP页面中得以交给八个page指令,而且import是能够另行出现的

   <%@ page import=”java.util.*”
%>

   <%@ page import=”java.next.*”
%>

* pageEncoding:钦赐当前页面包车型客车编码

  –>
假若pageEncoding没有点名,那么暗许为contentType的值;

  –>
尽管pageEncoding和contentType都不曾点名,那么暗许值为iso-8859-1
  
*
contentType:等同与调用response.setContentType(“text/html;charset=xxx”);

  –>
假诺没有点名contentType属性,那么默许为pageEncoding的值;

  –>
假若contentType和pageEncoding都没有点名,那么默认值为iso-8859-1

*
errorPage:若是当前页面出现格外,那么跳转到errorPage钦点的jsp页面。例如:<%@
page errorPage=”a.jsp” %>

*
isErrorPage:上面示例中钦定a.jsp为不当页面,但在a.jsp中不能动用内置对象exception,保有a.jsp中使用

<%@page
isErrorPage=”true”%>时,才能在a.jsp中央银行使不当页面。

*
autoFlush:当autoFlush为true时,表示out流缓冲区满时会活动刷新。暗许为true

*
buffer:钦点out流的缓冲区大小,暗中认可为8KB

*
isELIgnored:当前JSP页面是或不是忽略EL表明式,暗中认可为false,表示不忽视,即援助EL表明式

  1. page指令不常用的习性:

*
language:当前JSP编写翻译后的言语!暗许为java,当前也只能选取java

* info:当前JSP的认证新闻

*
isThreadSafe:当前JSP是还是不是履行只好单线程访问,默许为false,表示协助并发访问

*
session:当前页面是还是不是足以应用session,暗中认可为false,表示帮助session的采取。

include指令

语法:<%@include
file=”页面”%>

include指令的功力是富含内定的页面!在jsp被编写翻译成java文件从前会把多少个jsp文件合并,然后再编写翻译成一个java文件。

注意:

<%@include file=”<%=myfile%>”
%>

那是无法透过编写翻译的,因为myfile是贰个变量,它的值唯有在java编写翻译成class后实施时才能分明。

而include指令须求在jsp编写翻译java时就要显著包罗的是哪位页面,所以…

taglib指令

taglib指令是用来在近期jsp页面中程导弹入第贰方的标签库

<%@ taglib prefix=”c”
uri=”http://java.sun.com/jsp/jstl/core” %>

prefix:钦命标签前缀,这些事物能够随便起名

uri:内定第二方标签库的uri(唯一标识)

当然,必要先把第3方标签库所需jar包放到类路径中。

JSP动作标签

JSP动作标签是用来取代一部分java脚本,使非java开发人士也足以向jsp中添加动态新闻

<jsp:include>

譬如说:<jsp:include
page=”xxx”/>,用来含有钦命的页面。
比如说在a.jsp中留存如下内容:<jsp:include page=”b.jsp”/>
a.jsp和b.jsp分别编码成Servlet,然后在实施Servlet时才会履行李包裹括过程。那也是include指令与include标签的分别。

在意:<jsp:include
page=”<%=myfile%>”>,那是能够的!因为include指令是在推行时才成就的蕴藏,

在实践时曾经足以明确myfile这些变量的值。

该标签内部接纳的是RequestDispatcher#include()方法成功的涵盖

<jsp:forward>
譬如:<jsp:forward page=”xxx”/>,用来转发到钦命页面
比如在a.jsp中设有如下内容:<jsp:fowrad page=”b.jsp”/>
a.jsp中的内容不会显得在浏览器上,而只是展现b.jsp的始末。而且在<jsp:forwad>标签上边包车型大巴内容不会被实施。

<jsp:param>

该标签是<jsp:include>和<jsp:forward>的子标签,用来向其余页面传递参数。
<jsp:include page=”/b.jsp”>
<jsp:param value=”zhangSan”
name=”username”/> 
</jsp:include>
在b.jsp中得以应用request.getParameter(“username”)来获取参数值。

 

转自那里

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图