精华内容
下载资源
问答
  • Java内部

    2019-05-04 15:42:12
    Java语言允许在类中定义内部类,内部类就是在其它类内部定义的子类。内部类的功能主要有: 弥补一下单继承 可以实现量身定制,减少成本 联系外部环境与内部环境,内部类可访问外部类私有成员,类似JS中的闭包 对...

    Java语言允许在类中定义内部类,内部类就是在其它类内部定义的子类。内部类的功能主要有:

    1. 弥补一下单继承
    2. 可以实现量身定制,减少成本
    3. 联系外部环境与内部环境,内部类可访问外部类私有成员,类似JS中的闭包
    4. 对其他类不可见,保密性良好
    5. 具有闭包作用及在内部类中可以访问外部类所有成员甚至private修饰的,可以借助这个来获取外部类的private成员

    Java中的内部类主要分为四种:成员内部类,局部内部类,静态内部类,匿名内部类。

    成员内部类

    成员内部类和成员变量一样,属于类的全局成员。

    实例的内部类中存在对外部类的引用,即存在外部类的地址。这种内部类可以用四种类修饰符以及static和final,(外部类不可以用abstract与static或final连用)
    应用格式:外部类.内部类 内部类的变量名=new 外部类.().new 内部类();
    内部类通过外部类的实例来调用内部类的构造器实例化。
    使用的时候需要绑定。

    局部内部类

    通常用来返回接口。
    不可以用public、private,不包含static(不包含静态变量)。
    定义了接口,接口没有构造器,无法返回对应对象,所以不能返回接口对象,但是可以返回实现了接口的对象,通过获取返回的局部内部类的对象来调用重写方法,局部内部类访问局部变量必须加final。(这是因为内部存储的是常量,局部变量调用完毕消失,局部对象没有立即消失)

    静态内部类

    静态内部类用关键字static修饰。它与外部类没有什么区别,只是形式不同,可以定义static和非static这两种成员
    实例化方法,不用刻意去实例化,直接类名.方法,直接当对象用可以访问静态成员,但是只能调用类方法。
    静态内部类不可以访问外部非静态成员,但是可以创建一个外部类来访问,没有外部类引用。

    匿名内部类

    匿名内部类就是没有名称的内部类,它经常被用在Swing程序设计中的事件监听处理。
    用ClassName的子类创造对象,并且子类类体和对象的创建被组合在一起,具有针对性。
    前提,必须实现一个父类实现一个接口,它可以是一个类,也可以是一个接口
    匿名类一定是内部类,
    功能:

    1. 简化了代码编写
    2. 实现了量身定制
      用法:
    3. 省略了一个类的书写,并且匿名内部类能用在接口上,
    4. 一个抽象类和一个接口,那么子类中的方法都可以用静态匿名内部类实现,最常用于多线程实现,因为多线程实现必须继承Thread类和继承Runnable接口
      他没有访问修饰符,因为他没有直接开辟一个内部类,然后实现接口,重写方法返回实例,他直接new了一个接口的出现。
    展开全文
  • 前一天我们借助Java语言设计了一种专用的虚拟机,用于执行中间代码。从内部来看,该虚拟机通过Java语言的Object类型来表示所有类型的值,整数也将由Integer对象表现。不可否认,这是程序执行速度较慢的一个重要原因 ...

    笔记、源码同步在github上,欢迎Star,蟹蟹~


    前一天我们借助Java语言设计了一种专用的虚拟机,用于执行中间代码。从内部来看,该虚拟机通过Java语言的Object类型来表示所有类型的值,整数也将由Integer对象表现。不可否认,这是程序执行速度较慢的一个重要原因

    今天我们将利用静态数据类型,尽可能以int类型的值来表示整数值。同时,我们将不再使用专用的虚拟机,而直接使用Java虚拟机。抽象语法树需要预先转换为Java二进制代码,不过,由于整数改为int表示,转换得到的Java二进制代码执行效率也会较高

    指定变量类型

    支持静态数据类型的程序设计语言特点是,它需要在声明变量与参数的同时指定它们的数据类型。如果语言支持类型推论,一部分甚至大部分的类型指定就能省略。不过,能省略并不表示它们就不需要指定数据类型

    静态语言有一些缺点。例如,即使有需要,数据类型不同的变量值之间也无法相互赋值,而日某此恋量的类型可能较为复杂,不易理解。不过,静态类型语言也有一些重要的优点

    • 通过数据类型检查,它能在一定程度上确保程序的正确性
    • 静态数据类型信息有助于提高程序的执行速度

    我们先来改进Stone语言的语法,使它能够支持数据类型声明。首先增加的是var语句。它用于定义一个新的变量,并指定该变量的初始值与数据类型

    var x : Int = 7
    

    上面的语句对变量x做了定义,它是一个Int类型的变量,初始值为7.需要注意的是,变量声明时初始值不得省略。变量名之后跟有冒号与数据类型都可以省略

    var x = 7
    

    规定,var语句支持声明Int、String与Any三种类型,Int类型表示整数,String类型表示字符串。Any同时包含整数与字符串这两种类型。也就是说,一个整数值既可以由Int表示,也能由Any类型表示,字符串也是如此

    Any类型的变量能够被赋以Int或string类型的值,反之则不行

    虽然Any类型也包含整数,但它只支持有限的算术操作。Any类型的值只能进行+运算。除此以外,-(减法)等运算都无法用于Any类型的值。例如,对于Any类型的变量x,即使它的值为整数3,表达式x-1依然会引起数据类型错误。这是因为,变量x属于Any类型并不能确保它的值一定是一个整数

    除了var语句,我们还将为函数定义语句添加参数及返回值的数据类型指定功能。例如

    def inc(n: int) : int {
        n + 1
    }
    

    函数inc接收一个Int类型的参数n,并返回一个Int类型的返回值。右括号)之后跟着的返回值的类型。与var语句类似,冒号:与后接的数据类型名称用于指定参数或返回值的类型,它们同样能够省略

    代码清单14.1列出了对Stone语法规则的一些修改,经过这些修改,Stone语言将能支持上述数据类型指定功能。与var语句对应的非终结符是variable。同时,我们需要为statement增加variable这一可能情况。此外,param与def的定义也需要修改,以支持非终结符type_tag

    代码清单14.2是与修改后的语法规则对应的语法分析器程序。代码清单14.3与代码清单14.4是新定义的抽象语法树节点的对象类型

    为了执行新增的var语句,我们通过代码清单14.5所示的修改器为Varstmnt类添加了eva1方法

    代码清单14.1 与数据类型相关的语法规则

    type_tag -> ":" IDENTIFIER
    variable -> "var" IDENTIFIER [ type_tag ] "=" expr
    param -> IDENTIFIER [ type_tag ]
    def -> "def" IDENTIFIER param_list [ type_tag ] block
    statment -> variable | "if" ... | "while" ... | simple
    

    代码清单14.2 TypedParser.java

    package Stone;
    import static Stone.Parser.rule;
    import Stone.ast.*;
    
    public class TypedParser extends FuncParser {
    	Parser typeTag = rule(TypeTag.class).sep(":").identifier(reserved);
    	Parser variable = rule(VarStmnt.class).sep("var").identifier(reserved).maybe(typeTag).sep("=").ast(expr);
    
    	public TypedParser() {
    		reserved.add(":");
    		param.maybe(typeTag);
    		def.reset().sep("def").identifier(reserved).ast(paramList).maybe(typeTag).ast(block);
    		statement.insertChoice(variable);
    	}
    }
    

    代码清单14.3 VarStmnt.java

    package Stone.ast;
    import java.util.List;
    
    public class VarStmnt extends ASTList {
    	public VarStmnt(List<ASTree> c) {
    		super(c);
    	}
    
    	public String name() {
    		return ((ASTLeaf) child(0)).token().getText();
    	}
    
    	public TypeTag type() {
    		return (TypeTag) child(1);
    	}
    
    	public ASTree initializer() {
    		return child(2);
    	}
    
    	public String toString() {
    		return "(var " + name() + " " + type() + " " + initializer() + ")";
    	}
    }
    

    代码清单14.4 TypeTag.java

    package Stone.ast;
    import java.util.List;
    
    public class TypeTag extends ASTList {
    	public static final String UNDEF = "<Undef>";
    
    	public TypeTag(List<ASTree> c) {
    		super(c);
    	}
    
    	public String type() {
    		if (numChildren() > 0)
    			return ((ASTLeaf) child(0)).token().getText();
    		else
    			return UNDEF;
    	}
    
    	public String toString() {
    		return ":" + type();
    	}
    }
    

    代码清单14.5 TypedEvaluator.java

    package chap14;
    import java.util.List;
    import javassist.gluonj.*;
    import Stone.ast.*;
    import chap11.EnvOptimizer;
    import chap11.Symbols;
    import chap11.EnvOptimizer.ASTreeOptEx;
    import chap6.Environment;
    import chap6.BasicEvaluator.ASTreeEx;
    
    @Require(EnvOptimizer.class)
    @Reviser
    public class TypedEvaluator {
    	@Reviser
    	public static class DefStmntEx extends EnvOptimizer.DefStmntEx {
    		public DefStmntEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeTag type() {
    			return (TypeTag) child(2);
    		}
    
    		@Override
    		public BlockStmnt body() {
    			return (BlockStmnt) child(3);
    		}
    
    		@Override
    		public String toString() {
    			return "(def " + name() + " " + parameters() + " " + type() + " " + body() + ")";
    		}
    	}
    
    	@Reviser
    	public static class ParamListEx extends EnvOptimizer.ParamsEx {
    		public ParamListEx(List<ASTree> c) {
    			super(c);
    		}
    
    		@Override
    		public String name(int i) {
    			return ((ASTLeaf) child(i).child(0)).token().getText();
    		}
    
    		public TypeTag typeTag(int i) {
    			return (TypeTag) child(i).child(1);
    		}
    	}
    
    	@Reviser
    	public static class VarStmntEx extends VarStmnt {
    		protected int index;
    
    		public VarStmntEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public void lookup(Symbols syms) {
    			index = syms.putNew(name());
    			((ASTreeOptEx) initializer()).lookup(syms);
    		}
    
    		public Object eval(Environment env) {
    			Object value = ((ASTreeEx) initializer()).eval(env);
    			((EnvOptimizer.EnvEx2) env).put(0, index, value);
    			return value;
    		}
    	}
    }
    

    通过数据类型检查发现错误

    为了实现数据类型检查功能,我们要为抽象语法树的节点类添加typeCheck方法。该方法能够对数据类型进行检查,它与用于执行程序的eval方法非常类似,都会从抽象语法树的根节点开始递归调用自身,完成整棵语法树的遍历

    以x-2为例,调用根节点对象的typeCheck方法将返回该表达式的数据类型。变量x的数据类型由typeCheck方法的数据类型环境参数决定。eval方法的环境参数是由变量名与对应的值组成的键值对,typeCheck方法的数据类型环境则是由变量名与对应的数据类型组成的键值对

    类型指派规则看似复杂,其实它的核心是怎样根据各条表达式的子表达式类型,计算该表达式自身的类型。正如eval方法实现了表达式值的计算,typeCheck方法将实现对各个抽象法树节点类的数据类型的计算

    例如,对于单目减法运算表达式-(x*2),其子表达式(x*2)是-运算符的操作数,必须为Int类型。于是,整个单目运算表达式也将是Int类型。这就是类型指派规则

    双目运算表达式的类型指派规则稍有些复杂。首先,如果运算符两侧的子表达式都是Int类型,整个双目运算表达式也将是Int类型。对于+表达式,如果两侧都是String类型,整个表达式则是String类型,否则为Any类型。这使+运算符能够用于字符串连接运算。还有一种特殊情况是=运算符。对于=运算符,如果左右两侧的类型一致,整个赋值表达式的类型将与子表达式相同。如果左侧是一个新出现的变量,尚无特定的数据类型,该变量将被指定为与右侧相同的类型

    代码清单14.6是用于添加typeCheck方法的修改器。代码清单14.7是用于表示数据类型环境的TypeEnv类的定义。typeCheck方法在遇到类型错误时将抛出TypeException异常。代码清单14.8是该异常的定义

    代码清单14.9中,TypeInfo类的对象表示数据类型。该类定义了ANY、INT与STRING这三个static字段。它们都是TypeInfo类型的值,表示各自对应的数据类型。此外,该类还定义了UnknownType与Functionrype这两个嵌套子类。前者表示程序省略了类型指定,并暂且采用了与ANY相同的实现逻辑

    第二个嵌套类FunctionType用于表示函数的类型。函数的类型通过参数序列的类型与返回值的类型表现。例如,假设某个函数将接收Int类型与Any类型的参数,并返回string类型的返回值。这样一来,我们就可以称它是一个“依次接收Int与Any类型的参数且返回值为string类型”的函数

    抽象语法树各节点类的typeCheck方法在计算类型时,将首先递归调用子表达式的typeCheck方法。如果没有子表达式,则调用TypeInfo对象的assertSubtypeOf方法,确认它是否满足类型指派规则的前提条件。例如,在检查由=运算符构成的赋值表达式时,typeCheck方法将像下面这样,对表示左侧类型的type与表示右侧类型的valueType调用assertSubtypeOf方法

    代码清单14.6 TypeChecker.java

    package chap14;
    import java.util.List;
    import chap7.FuncEvaluator;
    import chap11.EnvOptimizer;
    import Stone.Token;
    import static javassist.gluonj.GluonJ.revise;
    import Stone.ast.*;
    import javassist.gluonj.*;
    
    @Require(TypedEvaluator.class)
    @Reviser
    public class TypeChecker {
    	@Reviser
    	public static abstract class ASTreeTypeEx extends ASTree {
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			return null;
    		}
    	}
    
    	@Reviser
    	public static class NumberEx extends NumberLiteral {
    		public NumberEx(Token t) {
    			super(t);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			return TypeInfo.INT;
    		}
    	}
    
    	@Reviser
    	public static class StringEx extends StringLiteral {
    		public StringEx(Token t) {
    			super(t);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			return TypeInfo.STRING;
    		}
    	}
    
    	@Reviser
    	public static class NameEx2 extends EnvOptimizer.NameEx {
    		protected TypeInfo type;
    
    		public NameEx2(Token t) {
    			super(t);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			type = tenv.get(nest, index);
    			if (type == null)
    				throw new TypeException("undefined name: " + name(), this);
    			else
    				return type;
    		}
    
    		public TypeInfo typeCheckForAssign(TypeEnv tenv, TypeInfo valueType) throws TypeException {
    			type = tenv.get(nest, index);
    			if (type == null) {
    				type = valueType;
    				tenv.put(0, index, valueType);
    				return valueType;
    			} else {
    				valueType.assertSubtypeOf(type, tenv, this);
    				return type;
    			}
    		}
    	}
    
    	@Reviser
    	public static class NegativeEx extends NegativeExpr {
    		public NegativeEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			TypeInfo t = ((ASTreeTypeEx) operand()).typeCheck(tenv);
    			t.assertSubtypeOf(TypeInfo.INT, tenv, this);
    			return TypeInfo.INT;
    		}
    	}
    
    	@Reviser
    	public static class BinaryEx extends BinaryExpr {
    		protected TypeInfo leftType, rightType;
    
    		public BinaryEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			String op = operator();
    			if ("=".equals(op))
    				return typeCheckForAssign(tenv);
    			else {
    				leftType = ((ASTreeTypeEx) left()).typeCheck(tenv);
    				rightType = ((ASTreeTypeEx) right()).typeCheck(tenv);
    				if ("+".equals(op))
    					return leftType.plus(rightType, tenv);
    				else if ("==".equals(op))
    					return TypeInfo.INT;
    				else {
    					leftType.assertSubtypeOf(TypeInfo.INT, tenv, this);
    					rightType.assertSubtypeOf(TypeInfo.INT, tenv, this);
    					return TypeInfo.INT;
    				}
    			}
    		}
    
    		protected TypeInfo typeCheckForAssign(TypeEnv tenv) throws TypeException {
    			rightType = ((ASTreeTypeEx) right()).typeCheck(tenv);
    			ASTree le = left();
    			if (le instanceof Name)
    				return ((NameEx2) le).typeCheckForAssign(tenv, rightType);
    			else
    				throw new TypeException("bad assignment", this);
    		}
    	}
    
    	@Reviser
    	public static class BlockEx extends BlockStmnt {
    		TypeInfo type;
    
    		public BlockEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			type = TypeInfo.INT;
    			for (ASTree t : this)
    				if (!(t instanceof NullStmnt))
    					type = ((ASTreeTypeEx) t).typeCheck(tenv);
    			return type;
    		}
    	}
    
    	@Reviser
    	public static class IfEx extends IfStmnt {
    		public IfEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			TypeInfo condType = ((ASTreeTypeEx) condition()).typeCheck(tenv);
    			condType.assertSubtypeOf(TypeInfo.INT, tenv, this);
    			TypeInfo thenType = ((ASTreeTypeEx) thenBlock()).typeCheck(tenv);
    			TypeInfo elseType;
    			ASTree elseBk = elseBlock();
    			if (elseBk == null)
    				elseType = TypeInfo.INT;
    			else
    				elseType = ((ASTreeTypeEx) elseBk).typeCheck(tenv);
    			return thenType.union(elseType, tenv);
    		}
    	}
    
    	@Reviser
    	public static class WhileEx extends WhileStmnt {
    		public WhileEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			TypeInfo condType = ((ASTreeTypeEx) condition()).typeCheck(tenv);
    			condType.assertSubtypeOf(TypeInfo.INT, tenv, this);
    			TypeInfo bodyType = ((ASTreeTypeEx) body()).typeCheck(tenv);
    			return bodyType.union(TypeInfo.INT, tenv);
    		}
    	}
    
    	@Reviser
    	public static class DefStmntEx2 extends TypedEvaluator.DefStmntEx {
    		protected TypeInfo.FunctionType funcType;
    		protected TypeEnv bodyEnv;
    
    		public DefStmntEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			TypeInfo[] params = ((ParamListEx2) parameters()).types();
    			TypeInfo retType = TypeInfo.get(type());
    			funcType = TypeInfo.function(retType, params);
    			TypeInfo oldType = tenv.put(0, index, funcType);
    			if (oldType != null)
    				throw new TypeException("function redefinition: " + name(), this);
    			bodyEnv = new TypeEnv(size, tenv);
    			for (int i = 0; i < params.length; i++)
    				bodyEnv.put(0, i, params[i]);
    			TypeInfo bodyType = ((ASTreeTypeEx) revise(body())).typeCheck(bodyEnv);
    			bodyType.assertSubtypeOf(retType, tenv, this);
    			return funcType;
    		}
    	}
    
    	@Reviser
    	public static class ParamListEx2 extends TypedEvaluator.ParamListEx {
    		public ParamListEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo[] types() throws TypeException {
    			int s = size();
    			TypeInfo[] result = new TypeInfo[s];
    			for (int i = 0; i < s; i++)
    				result[i] = TypeInfo.get(typeTag(i));
    			return result;
    		}
    	}
    
    	@Reviser
    	public static class PrimaryEx2 extends FuncEvaluator.PrimaryEx {
    		public PrimaryEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			return typeCheck(tenv, 0);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv, int nest) throws TypeException {
    			if (hasPostfix(nest)) {
    				TypeInfo target = typeCheck(tenv, nest + 1);
    				return ((PostfixEx) postfix(nest)).typeCheck(tenv, target);
    			} else
    				return ((ASTreeTypeEx) operand()).typeCheck(tenv);
    		}
    	}
    
    	@Reviser
    	public static abstract class PostfixEx extends Postfix {
    		public PostfixEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public abstract TypeInfo typeCheck(TypeEnv tenv, TypeInfo target) throws TypeException;
    	}
    
    	@Reviser
    	public static class ArgumentsEx extends Arguments {
    		protected TypeInfo[] argTypes;
    		protected TypeInfo.FunctionType funcType;
    
    		public ArgumentsEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv, TypeInfo target) throws TypeException {
    			if (!(target instanceof TypeInfo.FunctionType))
    				throw new TypeException("bad function", this);
    			funcType = (TypeInfo.FunctionType) target;
    			TypeInfo[] params = funcType.parameterTypes;
    			if (size() != params.length)
    				throw new TypeException("bad number of arguments", this);
    			argTypes = new TypeInfo[params.length];
    			int num = 0;
    			for (ASTree a : this) {
    				TypeInfo t = argTypes[num] = ((ASTreeTypeEx) a).typeCheck(tenv);
    				t.assertSubtypeOf(params[num++], tenv, this);
    			}
    			return funcType.returnType;
    		}
    	}
    
    	@Reviser
    	public static class VarStmntEx2 extends TypedEvaluator.VarStmntEx {
    		protected TypeInfo varType, valueType;
    
    		public VarStmntEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			if (tenv.get(0, index) != null)
    				throw new TypeException("duplicate variable: " + name(), this);
    			varType = TypeInfo.get(type());
    			tenv.put(0, index, varType);
    			valueType = ((ASTreeTypeEx) initializer()).typeCheck(tenv);
    			valueType.assertSubtypeOf(varType, tenv, this);
    			return varType;
    		}
    	}
    }
    

    代码清单14.7 TypeEnv.java

    package chap14;
    import java.util.Arrays;
    import Stone.StoneException;
    
    public class TypeEnv {
    	protected TypeEnv outer;
    	protected TypeInfo[] types;
    
    	public TypeEnv() {
    		this(8, null);
    	}
    
    	public TypeEnv(int size, TypeEnv out) {
    		outer = out;
    		types = new TypeInfo[size];
    	}
    
    	public TypeInfo get(int nest, int index) {
    		if (nest == 0)
    			if (index < types.length)
    				return types[index];
    			else
    				return null;
    		else if (outer == null)
    			return null;
    		else
    			return outer.get(nest - 1, index);
    	}
    
    	public TypeInfo put(int nest, int index, TypeInfo value) {
    		TypeInfo oldValue;
    		if (nest == 0) {
    			access(index);
    			oldValue = types[index];
    			types[index] = value;
    			return oldValue; // may be null
    		} else if (outer == null)
    			throw new StoneException("no outer type environment");
    		else
    			return outer.put(nest - 1, index, value);
    	}
    
    	protected void access(int index) {
    		if (index >= types.length) {
    			int newLen = types.length * 2;
    			if (index >= newLen)
    				newLen = index + 1;
    			types = Arrays.copyOf(types, newLen);
    		}
    	}
    }
    

    代码清单14.8 TypeException.java

    package chap14;
    import Stone.ast.ASTree;
    
    public class TypeException extends Exception {
    	public TypeException(String msg, ASTree t) {
    		super(msg + " " + t.location());
    	}
    }
    

    代码清单14.9 TypeInfo.java

    package chap14;
    import Stone.ast.ASTree;
    import Stone.ast.TypeTag;
    
    public class TypeInfo {
    	public static final TypeInfo ANY = new TypeInfo() {
    		@Override
    		public String toString() {
    			return "Any";
    		}
    	};
    	public static final TypeInfo INT = new TypeInfo() {
    		@Override
    		public String toString() {
    			return "Int";
    		}
    	};
    	public static final TypeInfo STRING = new TypeInfo() {
    		@Override
    		public String toString() {
    			return "String";
    		}
    	};
    
    	public TypeInfo type() {
    		return this;
    	}
    
    	public boolean match(TypeInfo obj) {
    		return type() == obj.type();
    	}
    
    	public boolean subtypeOf(TypeInfo superType) {
    		superType = superType.type();
    		return type() == superType || superType == ANY;
    	}
    
    	public void assertSubtypeOf(TypeInfo type, TypeEnv env, ASTree where) throws TypeException {
    		if (!subtypeOf(type))
    			throw new TypeException("type mismatch: cannot convert from " + this + " to " + type, where);
    	}
    
    	public TypeInfo union(TypeInfo right, TypeEnv tenv) {
    		if (match(right))
    			return type();
    		else
    			return ANY;
    	}
    
    	public TypeInfo plus(TypeInfo right, TypeEnv tenv) {
    		if (INT.match(this) && INT.match(right))
    			return INT;
    		else if (STRING.match(this) || STRING.match(right))
    			return STRING;
    		else
    			return ANY;
    	}
    
    	public static TypeInfo get(TypeTag tag) throws TypeException {
    		String tname = tag.type();
    		if (INT.toString().equals(tname))
    			return INT;
    		else if (STRING.toString().equals(tname))
    			return STRING;
    		else if (ANY.toString().equals(tname))
    			return ANY;
    		else if (TypeTag.UNDEF.equals(tname))
    			return new UnknownType();
    		else
    			throw new TypeException("unknown type " + tname, tag);
    	}
    
    	public static FunctionType function(TypeInfo ret, TypeInfo... params) {
    		return new FunctionType(ret, params);
    	}
    
    	public boolean isFunctionType() {
    		return false;
    	}
    
    	public FunctionType toFunctionType() {
    		return null;
    	}
    
    	public boolean isUnknownType() {
    		return false;
    	}
    
    	public UnknownType toUnknownType() {
    		return null;
    	}
    
    	public static class UnknownType extends TypeInfo {
    		@Override
    		public TypeInfo type() {
    			return ANY;
    		}
    
    		@Override
    		public String toString() {
    			return type().toString();
    		}
    
    		@Override
    		public boolean isUnknownType() {
    			return true;
    		}
    
    		@Override
    		public UnknownType toUnknownType() {
    			return this;
    		}
    	}
    
    	public static class FunctionType extends TypeInfo {
    		public TypeInfo returnType;
    		public TypeInfo[] parameterTypes;
    
    		public FunctionType(TypeInfo ret, TypeInfo... params) {
    			returnType = ret;
    			parameterTypes = params;
    		}
    
    		@Override
    		public boolean isFunctionType() {
    			return true;
    		}
    
    		@Override
    		public FunctionType toFunctionType() {
    			return this;
    		}
    
    		@Override
    		public boolean match(TypeInfo obj) {
    			if (!(obj instanceof FunctionType))
    				return false;
    			FunctionType func = (FunctionType) obj;
    			if (parameterTypes.length != func.parameterTypes.length)
    				return false;
    			for (int i = 0; i < parameterTypes.length; i++)
    				if (!parameterTypes[i].match(func.parameterTypes[i]))
    					return false;
    			return returnType.match(func.returnType);
    		}
    
    		@Override
    		public String toString() {
    			StringBuilder sb = new StringBuilder();
    			if (parameterTypes.length == 0)
    				sb.append("Unit");
    			else
    				for (int i = 0; i < parameterTypes.length; i++) {
    					if (i > 0)
    						sb.append(" * ");
    					sb.append(parameterTypes[i]);
    				}
    			sb.append(" -> ").append(returnType);
    			return sb.toString();
    		}
    	}
    }
    

    运行程序时执行类型检查

    至此,Stone语言处理器已经能够支持类型检查,我们先来试一下在运行程序时执行类型检查。代码清单14.10是新的解释器。它与之前的解释器大同小异,唯一的区别在于会在调用eval方法执行输入的程序之前,通过typecheck方法对数据类型执行检查。也就是说,该解释器会依次对输入的程序调用lookup、typeCheck与eval方法。此外,在最终显示eval方法的返回值时,它将同时显示typeCheck方法的返回值,即eval方法返回值的数据类型

    代码清单14.11是该解释器的启动程序。它应用了Typechecker修改器(及其依赖的其他修改器)

    在向环境添加原生函数时,我们还要向数据类型环境添加该原生函数的数据类型。代码清单14.12中的程序能实现这一处理。代码清单14.10中的解释器没有像之前那样使用第八天代码清单8.3中的Natives类,将使用代码清单14.13的程序。代码清单14.13~代码清单14.17是新增的原生函数。与之前不同,这些原生函数各自具有单独的类,且函数本身都被命名为m。这是为了之后将Stone语言的程序转换为Java二进制代码而做的准备

    启动解释器,试着执行一下程序

    def fact(n: Int) : Int {
        if n > 1 {
            n * fact(n - 1)
        } else {
            1
        }
    }
    fact 5
    

    执行结果如下所示:

    => fact : Int -> Int
    => 120 : Int
    

    第1行定义了函数fact,并表明它是一个接收Int类型参数,返回Int类型结果的函数。最后一行以5为参数调用了fact,得到一个Int类型的返回值120

    代码清单14.10 TypedInterpreter.java

    package chap14;
    import Stone.BasicParser;
    import Stone.CodeDialog;
    import Stone.Lexer;
    import Stone.Token;
    import Stone.TypedParser;
    import Stone.ParseException;
    import Stone.ast.ASTree;
    import Stone.ast.NullStmnt;
    import chap11.EnvOptimizer;
    import chap11.ResizableArrayEnv;
    import chap6.BasicEvaluator;
    import chap6.Environment;
    
    public class TypedInterpreter {
    	public static void main(String[] args) throws ParseException, TypeException {
    		TypeEnv te = new TypeEnv();
    		run(new TypedParser(), new TypedNatives(te).environment(new ResizableArrayEnv()), te);
    	}
    
    	public static void run(BasicParser bp, Environment env, TypeEnv typeEnv) throws ParseException, TypeException {
    		Lexer lexer = new Lexer(new CodeDialog());
    		while (lexer.peek(0) != Token.EOF) {
    			ASTree tree = bp.parse(lexer);
    			if (!(tree instanceof NullStmnt)) {
    				((EnvOptimizer.ASTreeOptEx) tree).lookup(((EnvOptimizer.EnvEx2) env).symbols());
    				TypeInfo type = ((TypeChecker.ASTreeTypeEx) tree).typeCheck(typeEnv);
    				Object r = ((BasicEvaluator.ASTreeEx) tree).eval(env);
    				System.out.println("=> " + r + " : " + type);
    			}
    		}
    	}
    }
    

    代码清单14.11 TypedRunner.java

    package chap14;
    import javassist.gluonj.util.Loader;
    import chap8.NativeEvaluator;
    
    public class TypedRunner {
    	public static void main(String[] args) throws Throwable {
    		Loader.run(TypedInterpreter.class, args, TypeChecker.class, NativeEvaluator.class);
    	}
    }
    

    代码清单14.12 TypedNatives.java

    package chap14;
    import chap6.Environment;
    import chap8.Natives;
    import chap11.EnvOptimizer.EnvEx2;
    
    public class TypedNatives extends Natives {
    	protected TypeEnv typeEnv;
    
    	public TypedNatives(TypeEnv te) {
    		typeEnv = te;
    	}
    
    	protected void append(Environment env, String name, Class<?> clazz, String methodName, TypeInfo type,
    			Class<?>... params) {
    		append(env, name, clazz, methodName, params);
    		int index = ((EnvEx2) env).symbols().find(name);
    		typeEnv.put(0, index, type);
    	}
    
    	protected void appendNatives(Environment env) {
    		append(env, "print", chap14.java.print.class, "m", TypeInfo.function(TypeInfo.INT, TypeInfo.ANY), Object.class);
    		append(env, "read", chap14.java.read.class, "m", TypeInfo.function(TypeInfo.STRING));
    		append(env, "length", chap14.java.length.class, "m", TypeInfo.function(TypeInfo.INT, TypeInfo.STRING),
    				String.class);
    		append(env, "toInt", chap14.java.toInt.class, "m", TypeInfo.function(TypeInfo.INT, TypeInfo.ANY), Object.class);
    		append(env, "currentTime", chap14.java.currentTime.class, "m", TypeInfo.function(TypeInfo.INT));
    	}
    }
    

    代码清单14.13 currentTime.java

    package chap14.java;
    import chap11.ArrayEnv;
    
    public class currentTime {
    	private static long startTime = System.currentTimeMillis();
    
    	public static int m(ArrayEnv env) {
    		return m();
    	}
    
    	public static int m() {
    		return (int) (System.currentTimeMillis() - startTime);
    	}
    }
    

    代码清单14.14 length.java

    package chap14.java;
    import chap11.ArrayEnv;
    
    public class length {
    	public static int m(ArrayEnv env, String s) {
    		return m(s);
    	}
    
    	public static int m(String s) {
    		return s.length();
    	}
    }
    

    代码清单14.15 print.java

    package chap14.java;
    import chap11.ArrayEnv;
    
    public class print {
    	public static int m(ArrayEnv env, Object obj) {
    		return m(obj);
    	}
    
    	public static int m(Object obj) {
    		System.out.println(obj.toString());
    		return 0;
    	}
    }
    

    代码清单14.16 read.java

    package chap14.java;
    import chap11.ArrayEnv;
    import javax.swing.JOptionPane;
    
    public class read {
    	public static String m(ArrayEnv env) {
    		return m();
    	}
    
    	public static String m() {
    		return JOptionPane.showInputDialog(null);
    	}
    }
    

    代码清单14.17 toInt.java

    package chap14.java;
    import chap11.ArrayEnv;
    
    public class toInt {
    	public static int m(ArrayEnv env, Object value) {
    		return m(value);
    	}
    
    	public static int m(Object value) {
    		if (value instanceof String)
    			return Integer.parseInt((String) value);
    		else if (value instanceof Integer)
    			return ((Integer) value).intValue();
    		else
    			throw new NumberFormatException(value.toString());
    	}
    }
    

    对类型省略的变量进行类型推论

    之前,如果没有明确指定变量或参数的类型,我们将默认它们是Any类型。然而,Any类型的值无法进行减法与乘法计算,非常不便

    为此,如果没有明确指定数据类型,我们就需要调查该变量或参数的使用方式,推测恰当的数据类型。这就是类型推论(type inference)。例如,如果某个变量出现在减法表达式的左侧或右侧,我们就能推测出它是一个Int类型的变量。之后,如果数据类型省略,我们将暂时把它记为Unknown类型(类型不明的类型),并通过类型推论确定它具体是什么类型

    类型推论算法与类型检查算法大同小异。在执行类型检查时,语言处理器常需要确认-运算符左右两侧的子表达式是否都是Int类型,如果不是Int类型就会发生类型错误。不难想象,为了避免发生类型错误,我们需要将Unknown类型的子表达式视为Int类型处理。这样一来,最初是Unknown类型的值将随着类型检查的进行,逐渐被指定为具体的数据类型

    对于上面的减法表达式,我们可以很容易地推测出Unknown具体指代的类型,但是有时,要确定一个值的类型并非易事。例如,在下面的赋值表达式中,变量x与y都没有被指定类型

    x = y
    

    这时,变量y要么与x的类型相同,要么是x类型的子类。然而,如果无法确定具体的类型,仅凭这些条件,我们无法推测出更加具体的结果

    因此,我们只能推迟类型推论处理,等待获取进一步的信息。我们需要暂时记录这条赋值表达式中包含的信息,通常,这些信息以方程式的形式表现。首先,对于没有明确指定且尚不能推测出数据类型的变量与参数,我们将以tx、ty等变量表示。于是,该赋值表达式包含的信息就与下面的式子等价

    ty = tx
    

    这里的<表示子类关系。将数据类型信息以方程式的形式表现之后,类型推论的适用范围将更广。例如,如果在执行类型检查时遇到形如x-1的表达式,我们可以通过同样的思路,用下面的方程式表示其中包含的类型条件

    tx = Int
    

    减法两侧必须都是Int类型的值。连立两个方程式可得ty≤Int,又由于Int不含子类,因此可知tr、th都是Int类型的值

    不难发现,类型推论的本质其实就是连立含有数据类型条件的方程式后求解。该连立方程式的解就是各个Unknown类型恋量的具体数据类型

    有些方程式可能含有多个解,我们无法据此确定某个变量的具体类型。方便起见,对于这种情况,Stone 语言将把变量指定为Any类型。例如,下面的函数id将在接收参数x后直接返回x的值,我们设参数x的类型为tx,函数id返回值的类型为tid,并连立方程式,解得tx ≤ tid

    def id(x) {
        x
    }
    

    代码清单14.18中的修改器将修改与类型推论处理相关的类。它修改了TypeEnv类、TypeInfo类及其子类UnknownType类。在此之前,TypeInfo类的assertSubtypeOf方法用于确认两种类型是否相同,或是否具有子类关系,如果不符合则抛出异常。修改后,如果遇到Unknown类型的值,该方法将为这两种类型建立方程式,并添加至数据类型环境TypeEnv对象中

    要最终完成类型推论的实现,除了代码清单14.18中提供的,我们还需要再使用一个修改器。对于函数内部的局部变量或参数,如果仅凭函数内部的类型推论,无法确定Unknown类型的具体结果,Stone语言将默认采用Any类型。代码清单14.19中的修改器实现了这一逻辑。该修改器覆盖了DefStmnt类的typeCheck方法,在函数体的类型检查结束时,尚且无法确定具体数据类型的Unknown类型全都置为了Any类型

    代码清单14.20是解释器的启动程序。为了支持类型推论功能,它在运行Stone语言解释器前将首先应用代码清单14.18与代码清单14.19中的修改器。代码清单14.20虽然没有显式地应用InferTypes修改器,但应用了InferFuncTypes修改器。由于InferFuncTypes修改器通过@Require隐式地应用了InferTypes等修改器,因此它们都会被一起应用于新的解释器

    代码清单14.18 InferTypes.java

    package chap14;
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import Stone.ast.ASTree;
    import javassist.gluonj.Reviser;
    import chap14.TypeInfo.UnknownType;
    
    @Reviser
    public class InferTypes {
    	@Reviser
    	public static class TypeInfoEx extends TypeInfo {
    		@Override
    		public void assertSubtypeOf(TypeInfo type, TypeEnv tenv, ASTree where) throws TypeException {
    			if (type.isUnknownType())
    				((UnknownTypeEx) type.toUnknownType()).assertSupertypeOf(this, tenv, where);
    			else
    				super.assertSubtypeOf(type, tenv, where);
    		}
    
    		@Override
    		public TypeInfo union(TypeInfo right, TypeEnv tenv) {
    			if (right.isUnknownType())
    				return right.union(this, tenv);
    			else
    				return super.union(right, tenv);
    		}
    
    		@Override
    		public TypeInfo plus(TypeInfo right, TypeEnv tenv) {
    			if (right.isUnknownType())
    				return right.plus(this, tenv);
    			else
    				return super.plus(right, tenv);
    		}
    	}
    
    	@Reviser
    	public static class UnknownTypeEx extends TypeInfo.UnknownType {
    		protected TypeInfo type = null;
    
    		public boolean resolved() {
    			return type != null;
    		}
    
    		public void setType(TypeInfo t) {
    			type = t;
    		}
    
    		@Override
    		public TypeInfo type() {
    			return type == null ? ANY : type;
    		}
    
    		@Override
    		public void assertSubtypeOf(TypeInfo t, TypeEnv tenv, ASTree where) throws TypeException {
    			if (resolved())
    				type.assertSubtypeOf(t, tenv, where);
    			else
    				((TypeEnvEx) tenv).addEquation(this, t);
    		}
    
    		public void assertSupertypeOf(TypeInfo t, TypeEnv tenv, ASTree where) throws TypeException {
    			if (resolved())
    				t.assertSubtypeOf(type, tenv, where);
    			else
    				((TypeEnvEx) tenv).addEquation(this, t);
    		}
    
    		@Override
    		public TypeInfo union(TypeInfo right, TypeEnv tenv) {
    			if (resolved())
    				return type.union(right, tenv);
    			else {
    				((TypeEnvEx) tenv).addEquation(this, right);
    				return right;
    			}
    		}
    
    		@Override
    		public TypeInfo plus(TypeInfo right, TypeEnv tenv) {
    			if (resolved())
    				return type.plus(right, tenv);
    			else {
    				((TypeEnvEx) tenv).addEquation(this, INT);
    				return right.plus(INT, tenv);
    			}
    		}
    	}
    
    	@Reviser
    	public static class TypeEnvEx extends TypeEnv {
    		public static class Equation extends ArrayList<UnknownType> {
    		}
    
    		protected List<Equation> equations = new LinkedList<Equation>();
    
    		public void addEquation(UnknownType t1, TypeInfo t2) {
    			// assert t1.unknown() == true
    			if (t2.isUnknownType())
    				if (((UnknownTypeEx) t2.toUnknownType()).resolved())
    					t2 = t2.type();
    			Equation eq = find(t1);
    			if (t2.isUnknownType())
    				eq.add(t2.toUnknownType());
    			else {
    				for (UnknownType t : eq)
    					((UnknownTypeEx) t).setType(t2);
    				equations.remove(eq);
    			}
    		}
    
    		protected Equation find(UnknownType t) {
    			for (Equation e : equations)
    				if (e.contains(t))
    					return e;
    			Equation e = new Equation();
    			e.add(t);
    			equations.add(e);
    			return e;
    		}
    	}
    }
    

    代码清单14.19 InferFuncTypes.java

    package chap14;
    import java.util.List;
    import chap14.TypeInfo.FunctionType;
    import chap14.TypeInfo.UnknownType;
    import chap14.InferTypes.UnknownTypeEx;
    import Stone.ast.ASTree;
    import javassist.gluonj.Require;
    import javassist.gluonj.Reviser;
    
    @Require({ TypeChecker.class, InferTypes.class })
    @Reviser
    public class InferFuncTypes {
    	@Reviser
    	public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 {
    		public DefStmntEx3(List<ASTree> c) {
    			super(c);
    		}
    
    		@Override
    		public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
    			FunctionType func = super.typeCheck(tenv).toFunctionType();
    			for (TypeInfo t : func.parameterTypes)
    				fixUnknown(t);
    			fixUnknown(func.returnType);
    			return func;
    		}
    
    		protected void fixUnknown(TypeInfo t) {
    			if (t.isUnknownType()) {
    				UnknownType ut = t.toUnknownType();
    				if (!((UnknownTypeEx) ut).resolved())
    					((UnknownTypeEx) ut).setType(TypeInfo.ANY);
    			}
    		}
    	}
    }
    

    代码清单14.20 InferRunner.java

    package chap14;
    import javassist.gluonj.util.Loader;
    import chap8.NativeEvaluator;
    
    public class InferRunner {
    	public static void main(String[] args) throws Throwable {
    		Loader.run(TypedInterpreter.class, args, InferFuncTypes.class, NativeEvaluator.class);
    	}
    }
    

    Java二进制代码转换

    获得了静态数据类型信息之后,我们将利用现有的库,实现Java二进制代码的转换

    为了对Java二进制代码进行操作,本章采用了一种名为Javassist的库。该库能够在程序执行过程中创建并载入新的类,并调用其中的方法。由于新增方法的定义能以Java源代码的形式传递给Javassist,因此我们无需在程序中生成Java二进制代码,非常方便。Javassist能自动编译接收的源代码,并将其转换为二进制代码

    代码清单14.21中的程序能够通过Javassist来定义新的方法。JavaLoader类的1oad方法将在接收类名与方法的定义后,对方法进行定义,并生成二进制代码,最后载入Java虚拟机。1oad方法的返回值是该类的Class对象

    代码清单14.21 JavaLoader.java

    package chap14;
    import Stone.StoneException;
    import javassist.CannotCompileException;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    
    public class JavaLoader {
    	protected ClassLoader loader;
    	protected ClassPool cpool;
    
    	public JavaLoader() {
    		cpool = new ClassPool(null);
    		cpool.appendSystemPath();
    		loader = new ClassLoader(this.getClass().getClassLoader()) {
    		};
    	}
    
    	public Class<?> load(String className, String method) {
    		// System.out.println(method);
    		CtClass cc = cpool.makeClass(className);
    		try {
    			cc.addMethod(CtMethod.make(method, cc));
    			return cc.toClass(loader, null);
    		} catch (CannotCompileException e) {
    			throw new StoneException(e.getMessage());
    		}
    	}
    }
    

    代码清单14.22中的JavaFunction类的对象用于表示函数

    代码清单14.22 JavaFunction.java

    package chap14;
    import Stone.StoneException;
    import chap7.Function;
    
    public class JavaFunction extends Function {
    	protected String className;
    	protected Class<?> clazz;
    
    	public JavaFunction(String name, String method, JavaLoader loader) {
    		super(null, null, null);
    		className = className(name);
    		clazz = loader.load(className, method);
    	}
    
    	public static String className(String name) {
    		return "chap14.java." + name;
    	}
    
    	public Object invoke(Object[] args) {
    		try {
    			return clazz.getDeclaredMethods()[0].invoke(null, args);
    		} catch (Exception e) {
    			throw new StoneException(e.getMessage());
    		}
    	}
    }
    

    由于使用Javassist,因此与其说是将抽象语法树转换为Java二进制代码,不如所是将它转换为Java源代码。例如,假设定义了一个Stone语言函数fact

    def fact(n) {
        if n < 2 {
            1
        } else {
            n * fact(n - 1)
        }
    }
    

    该函数将被转换为名为chap14.java.fact的类中的一个static方法

    public static int m(chap11.ArrayEnv env,int v0) {
        int res;
        if ((v0 < 2 ? 1 : 0) != 0) {
            res = 1;
        } else {
            res = (v0 * chap14.java.fact.m(env, (v0 - v1)));
        }
        return res;
    }
    

    chap14.java.fact类仅包含一个方法m。m这个方法名并没有什么特殊含义。该方法的第一个参数env是一个用于引用全局变量的环境,不过在该例中,fact函数不需要使用这个环境。m方法的第二个参数vo是fact函数的参数。在转换为Java语言的方法后,if语句有一条稍显冗长的条件表达式。该表达式由fact函数的定义直接翻译

    代码清单14.23中的修改器用于将函数转换为Java二进制代码。修改器起始处的ranslateExpr与returnZero是两个辅助方法,需由其他方法调用。EnvEx3与ArrayEnvEx修改器将向环境中添加新的字段,并通过它们保存JavaLoader对象

    在Java语言的转换过程中,Stone语言的Int、string与Any类型分别对应Java中的int、string与object类型。由于Stone语言的语法与Java较为相近,所以转换逻辑并不复杂,只需为每个变量添加静态数据类型即可

    代码清单14.23 ToJava.java

    package chap14;
    import java.util.ArrayList;
    import java.util.List;
    import chap11.ArrayEnv;
    import chap11.EnvOptimizer;
    import chap6.Environment;
    import chap7.FuncEvaluator;
    import Stone.StoneException;
    import Stone.Token;
    import Stone.ast.*;
    import javassist.gluonj.Require;
    import javassist.gluonj.Reviser;
    import static javassist.gluonj.GluonJ.revise;
    
    @Require(TypeChecker.class)
    @Reviser
    public class ToJava {
    	public static final String METHOD = "m";
    	public static final String LOCAL = "v";
    	public static final String ENV = "env";
    	public static final String RESULT = "res";
    	public static final String ENV_TYPE = "chap11.ArrayEnv";
    
    	public static String translateExpr(ASTree ast, TypeInfo from, TypeInfo to) {
    		return translateExpr(((ASTreeEx) ast).translate(null), from, to);
    	}
    
    	public static String translateExpr(String expr, TypeInfo from, TypeInfo to) {
    		from = from.type();
    		to = to.type();
    		if (from == TypeInfo.INT) {
    			if (to == TypeInfo.ANY)
    				return "new Integer(" + expr + ")";
    			else if (to == TypeInfo.STRING)
    				return "Integer.toString(" + expr + ")";
    		} else if (from == TypeInfo.ANY)
    			if (to == TypeInfo.STRING)
    				return expr + ".toString()";
    			else if (to == TypeInfo.INT)
    				return "((Integer)" + expr + ").intValue()";
    		return expr;
    	}
    
    	public static String returnZero(TypeInfo to) {
    		if (to.type() == TypeInfo.ANY)
    			return RESULT + "=new Integer(0);";
    		else
    			return RESULT + "=0;";
    	}
    
    	@Reviser
    	public static interface EnvEx3 extends EnvOptimizer.EnvEx2 {
    		JavaLoader javaLoader();
    	}
    
    	@Reviser
    	public static class ArrayEnvEx extends ArrayEnv {
    		public ArrayEnvEx(int size, Environment out) {
    			super(size, out);
    		}
    
    		protected JavaLoader jloader = new JavaLoader();
    
    		public JavaLoader javaLoader() {
    			return jloader;
    		}
    	}
    
    	@Reviser
    	public static abstract class ASTreeEx extends ASTree {
    		public String translate(TypeInfo result) {
    			return "";
    		}
    	}
    
    	@Reviser
    	public static class NumberEx extends NumberLiteral {
    		public NumberEx(Token t) {
    			super(t);
    		}
    
    		public String translate(TypeInfo result) {
    			return Integer.toString(value());
    		}
    	}
    
    	@Reviser
    	public static class StringEx extends StringLiteral {
    		public StringEx(Token t) {
    			super(t);
    		}
    
    		public String translate(TypeInfo result) {
    			StringBuilder code = new StringBuilder();
    			String literal = value();
    			code.append('"');
    			for (int i = 0; i < literal.length(); i++) {
    				char c = literal.charAt(i);
    				if (c == '"')
    					code.append("\\\"");
    				else if (c == '\\')
    					code.append("\\\\");
    				else if (c == '\n')
    					code.append("\\n");
    				else
    					code.append(c);
    			}
    			code.append('"');
    			return code.toString();
    		}
    	}
    
    	@Reviser
    	public static class NameEx3 extends TypeChecker.NameEx2 {
    		public NameEx3(Token t) {
    			super(t);
    		}
    
    		public String translate(TypeInfo result) {
    			if (type.isFunctionType())
    				return JavaFunction.className(name()) + "." + METHOD;
    			else if (nest == 0)
    				return LOCAL + index;
    			else {
    				String expr = ENV + ".get(0," + index + ")";
    				return translateExpr(expr, TypeInfo.ANY, type);
    			}
    		}
    
    		public String translateAssign(TypeInfo valueType, ASTree right) {
    			if (nest == 0)
    				return "(" + LOCAL + index + "=" + translateExpr(right, valueType, type) + ")";
    			else {
    				String value = ((ASTreeEx) right).translate(null);
    				return "chap14.Runtime.write" + type.toString() + "(" + ENV + "," + index + "," + value + ")";
    			}
    		}
    	}
    
    	@Reviser
    	public static class NegativeEx extends NegativeExpr {
    		public NegativeEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			return "-" + ((ASTreeEx) operand()).translate(null);
    		}
    	}
    
    	@Reviser
    	public static class BinaryEx2 extends TypeChecker.BinaryEx {
    		public BinaryEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			String op = operator();
    			if ("=".equals(op))
    				return ((NameEx3) left()).translateAssign(rightType, right());
    			else if (leftType.type() != TypeInfo.INT || rightType.type() != TypeInfo.INT) {
    				String e1 = translateExpr(left(), leftType, TypeInfo.ANY);
    				String e2 = translateExpr(right(), rightType, TypeInfo.ANY);
    				if ("==".equals(op))
    					return "chap14.Runtime.eq(" + e1 + "," + e2 + ")";
    				else if ("+".equals(op)) {
    					if (leftType.type() == TypeInfo.STRING || rightType.type() == TypeInfo.STRING)
    						return e1 + "+" + e2;
    					else
    						return "chap14.Runtime.plus(" + e1 + "," + e2 + ")";
    				} else
    					throw new StoneException("bad operator", this);
    			} else {
    				String expr = ((ASTreeEx) left()).translate(null) + op + ((ASTreeEx) right()).translate(null);
    				if ("<".equals(op) || ">".equals(op) || "==".equals(op))
    					return "(" + expr + "?1:0)";
    				else
    					return "(" + expr + ")";
    			}
    		}
    	}
    
    	@Reviser
    	public static class BlockEx2 extends TypeChecker.BlockEx {
    		public BlockEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			ArrayList<ASTree> body = new ArrayList<ASTree>();
    			for (ASTree t : this)
    				if (!(t instanceof NullStmnt))
    					body.add(t);
    			StringBuilder code = new StringBuilder();
    			if (result != null && body.size() < 1)
    				code.append(returnZero(result));
    			else
    				for (int i = 0; i < body.size(); i++)
    					translateStmnt(code, body.get(i), result, i == body.size() - 1);
    			return code.toString();
    		}
    
    		protected void translateStmnt(StringBuilder code, ASTree tree, TypeInfo result, boolean last) {
    			if (isControlStmnt(tree))
    				code.append(((ASTreeEx) tree).translate(last ? result : null));
    			else if (last && result != null)
    				code.append(RESULT).append('=').append(translateExpr(tree, type, result)).append(";\n");
    			else if (isExprStmnt(tree))
    				code.append(((ASTreeEx) tree).translate(null)).append(";\n");
    			else
    				throw new StoneException("bad expression statement", this);
    		}
    
    		protected static boolean isExprStmnt(ASTree tree) {
    			if (tree instanceof BinaryExpr)
    				return "=".equals(((BinaryExpr) tree).operator());
    			return tree instanceof PrimaryExpr || tree instanceof VarStmnt;
    		}
    
    		protected static boolean isControlStmnt(ASTree tree) {
    			return tree instanceof BlockStmnt || tree instanceof IfStmnt || tree instanceof WhileStmnt;
    		}
    	}
    
    	@Reviser
    	public static class IfEx extends IfStmnt {
    		public IfEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			StringBuilder code = new StringBuilder();
    			code.append("if(");
    			code.append(((ASTreeEx) condition()).translate(null));
    			code.append("!=0){\n");
    			code.append(((ASTreeEx) thenBlock()).translate(result));
    			code.append("} else {\n");
    			ASTree elseBk = elseBlock();
    			if (elseBk != null)
    				code.append(((ASTreeEx) elseBk).translate(result));
    			else if (result != null)
    				code.append(returnZero(result));
    			return code.append("}\n").toString();
    		}
    	}
    
    	@Reviser
    	public static class WhileEx extends WhileStmnt {
    		public WhileEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			String code = "while(" + ((ASTreeEx) condition()).translate(null) + "!=0){\n"
    					+ ((ASTreeEx) body()).translate(result) + "}\n";
    			if (result == null)
    				return code;
    			else
    				return returnZero(result) + "\n" + code;
    		}
    	}
    
    	@Reviser
    	public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 {
    		public DefStmntEx3(List<ASTree> c) {
    			super(c);
    		}
    
    		@Override
    		public Object eval(Environment env) {
    			String funcName = name();
    			JavaFunction func = new JavaFunction(funcName, translate(null), ((EnvEx3) env).javaLoader());
    			((EnvEx3) env).putNew(funcName, func);
    			return funcName;
    		}
    
    		public String translate(TypeInfo result) {
    			StringBuilder code = new StringBuilder("public static ");
    			TypeInfo returnType = funcType.returnType;
    			code.append(javaType(returnType)).append(' ');
    			code.append(METHOD).append("(chap11.ArrayEnv ").append(ENV);
    			for (int i = 0; i < funcType.parameterTypes.length; i++) {
    				code.append(',').append(javaType(funcType.parameterTypes[i])).append(' ').append(LOCAL).append(i);
    			}
    			code.append("){\n");
    			code.append(javaType(returnType)).append(' ').append(RESULT).append(";\n");
    			for (int i = funcType.parameterTypes.length; i < size; i++) {
    				TypeInfo t = bodyEnv.get(0, i);
    				code.append(javaType(t)).append(' ').append(LOCAL).append(i);
    				if (t.type() == TypeInfo.INT)
    					code.append("=0;\n");
    				else
    					code.append("=null;\n");
    			}
    			code.append(((ASTreeEx) revise(body())).translate(returnType));
    			code.append("return ").append(RESULT).append(";}");
    			return code.toString();
    		}
    
    		protected String javaType(TypeInfo t) {
    			if (t.type() == TypeInfo.INT)
    				return "int";
    			else if (t.type() == TypeInfo.STRING)
    				return "String";
    			else
    				return "Object";
    		}
    	}
    
    	@Reviser
    	public static class PrimaryEx2 extends FuncEvaluator.PrimaryEx {
    		public PrimaryEx2(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			return translate(0);
    		}
    
    		public String translate(int nest) {
    			if (hasPostfix(nest)) {
    				String expr = translate(nest + 1);
    				return ((PostfixEx) postfix(nest)).translate(expr);
    			} else
    				return ((ASTreeEx) operand()).translate(null);
    		}
    	}
    
    	@Reviser
    	public static abstract class PostfixEx extends Postfix {
    		public PostfixEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public abstract String translate(String expr);
    	}
    
    	@Reviser
    	public static class ArgumentsEx extends TypeChecker.ArgumentsEx {
    		public ArgumentsEx(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(String expr) {
    			StringBuilder code = new StringBuilder(expr);
    			code.append('(').append(ENV);
    			for (int i = 0; i < size(); i++)
    				code.append(',').append(translateExpr(child(i), argTypes[i], funcType.parameterTypes[i]));
    			return code.append(')').toString();
    		}
    
    		public Object eval(Environment env, Object value) {
    			if (!(value instanceof JavaFunction))
    				throw new StoneException("bad function", this);
    			JavaFunction func = (JavaFunction) value;
    			Object[] args = new Object[numChildren() + 1];
    			args[0] = env;
    			int num = 1;
    			for (ASTree a : this)
    				args[num++] = ((chap6.BasicEvaluator.ASTreeEx) a).eval(env);
    			return func.invoke(args);
    		}
    	}
    
    	@Reviser
    	public static class VarStmntEx3 extends TypeChecker.VarStmntEx2 {
    		public VarStmntEx3(List<ASTree> c) {
    			super(c);
    		}
    
    		public String translate(TypeInfo result) {
    			return LOCAL + index + "=" + translateExpr(initializer(), valueType, varType);
    		}
    	}
    }
    

    代码清单14.24 RunTime.java

    package chap14;
    import chap11.ArrayEnv;
    
    public class Runtime {
    	public static int eq(Object a, Object b) {
    		if (a == null)
    			return b == null ? 1 : 0;
    		else
    			return a.equals(b) ? 1 : 0;
    	}
    
    	public static Object plus(Object a, Object b) {
    		if (a instanceof Integer && b instanceof Integer)
    			return ((Integer) a).intValue() + ((Integer) b).intValue();
    		else
    			return a.toString().concat(b.toString());
    	}
    
    	public static int writeInt(ArrayEnv env, int index, int value) {
    		env.put(0, index, value);
    		return value;
    	}
    
    	public static String writeString(ArrayEnv env, int index, String value) {
    		env.put(0, index, value);
    		return value;
    	}
    
    	public static Object writeAny(ArrayEnv env, int index, Object value) {
    		env.put(0, index, value);
    		return value;
    	}
    }
    

    综合所有修改再次运行程序

    代码清单14.25是最新版的启动程序。该启动程序在运行Stone语言时将同时执行类型检查、类型推论以及Java二进制代码的转换

    代码清单14.25 JavaRunner.java

    package chap14;
    import javassist.gluonj.util.Loader;
    import chap8.NativeEvaluator;
    
    public class JavaRunner {
    	public static void main(String[] args) throws Throwable {
    		Loader.run(TypedInterpreter.class, args, ToJava.class, InferFuncTypes.class, NativeEvaluator.class);
    	}
    }
    

    运行效果如下:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bu8keuth-1569714454261)(https://s1.ax1x.com/2018/12/23/FybWdg.gif#shadow)]
    相比较前几天的优化,今天的优化速度提升非常明显,前几天执行fib 33至少都要6秒,今天只用2ms

    第十四天的思维导图

    展开全文
  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 加载完类之后,在堆内存的方法区中就产生了一个Class...

    1、反射的理解

    Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

    加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

    Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!反射可以让java在运行期间决定造的是哪个类的对象,执行的哪个方法。

    2、动态语言 vs 静态语言

    动态语言:

    是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。

    主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

    静态语言:

    运行时结构不可变的语言就是静态语言。

    如Java、C、C++。

    3、编译型语言 vs解释性语言

    编译型语言:

    需通过编译器(compiler)将源代码编译成机器码,之后才能执行的语言。一般需经过编译(compile)、链接(linker)这两个步骤。编译是把源代码编译成机器码,链接是把各个模块的机器码和依赖库串连起来生成可执行文件。

    代表语言:C、C++、Pascal、Object-C以及最近很火的苹果新语言swift

    解释性语言:

    解释性语言的程序不需要编译,相比编译型语言省了道工序,解释性语言在运行程序的时候才逐行翻译。

    代表语言:JavaScript、Python、Erlang、PHP、Perl、Ruby

    混合型语言:

    Java语言虽然比较接近解释型语言的特征,但在执行之前已经预先进行一次预编译,生成的代码(字节码)是介于机器码和Java源代码之间的中介代码,运行的时候则由JVM(Java的虚拟机平台,可视为解释器)解释执行。(偏解释性)

    C#则是生成.net目标代码,实际执行时则由.net解释系统(就像JVM一样,也是一个虚拟机平台)进行执行。当然.net目标代码已经相当“低级”,比较接近机器语言了,所以仍将其视为编译语言。(偏编译)

    4、动态类型语言 vs 静态类型语言

    动态类型语言:

    动态类型语言和动态语言是完全不同的两个概念。动态类型语言是指在运行期间才去做数据类型检查的语言,说的是数据类型,动态语言说的是运行是改变结构,说的是代码结构。

    主要语言:Python、Ruby、Erlang、JavaScript、swift、PHP、Perl。

    静态类型语言:

    静态语言的数据类型是在编译其间确定的或者说运行之前确定的,编写代码的时候要明确确定变量的数据类型。

    主要语言:C、C++、C#、Java、Object-C。

    5、强类型语言 vs 弱类型语言

    强类型语言:

    强类型语言,一旦一个变量被指定了某个数据类型,如果不经过强制类型转换,那么它就永远是这个数据类型。你不能把一个整形变量当成一个字符串来处理。

    主要语言:Java、C#、Python、Object-C、Ruby

    弱类型语言:

    数据类型可以被忽略,一个变量可以赋不同数据类型的值。一旦给一个整型变量a赋一个字符串值,那么a就变成字符串类型。

    主要语言:JavaScript、PHP、C、C++(C和C++有争议,但是确实可以给一个字符变量赋整形值,可能初衷是强类型,形态上接近弱类型)

    展开全文
  • Reflection (反射)是被视为动态语言(就是有了反射,才让java动态)的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 加载完类之后,在堆内存的...

    1、Java反射机制概述

        Reflection (反射)是被视为动态语言(就是有了反射,才让java动态的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

        加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(类对象:一个类只有一个Class对象) ,这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

    补充:动态语言 和 静态语言

    (1)动态语言

            动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言: Object-C.C#、JavaScript, PHP,Python, Erlang..

    (2)静态语言

            与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java.C.C++。

    总结:Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活

    Exp:服务器已经跑起来了。前端Js发送请求想登陆,此时需要后台造登陆的对象;如果Js发送请求想注册,此时就需要后台造注册的对象,这就是动态运行造对象,此时就是用反射造对象。

    1.1 Java反射机制提供的功能

            在运行时判断任意一个对象所属的类

            在运行时构造任意一个类的对象

            在运行时判断任意一个类所具有的成员变量和方法

            在运行时获取泛型信息

            在运行时调用任意一个对象的成员变量和方法

            在运行时处理注解

            生成动态代理

    1.2  反射相关的主要API

            java.lang.Class:代表一个类(Class是类 class是关键字) Class类,描述类的类

            java.lang.reflect.Method:代表类的方法

            java.lang.reflect.Field:代表类的成员变量

            java.lang.reflect.Constructor:代表类的构造器

    2、关于 java.lang.Class类的理解

    类的加载过程:程序经过javac.exe 命令以后, 会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件(带main函数的类)进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为CLass的一个实例。

    说明:

    ① Class就对应着一个运行时类。即运行时,这个类就出来了。所以编译时就不用去new 一个 Class

    ② 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过exp中的3种方法来获取此运行时类

    Class对象可以是以下所有类型:

    ① 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

    ② interface,接口

    ③ [ ] 数组

    ④ enum:枚举

    ⑤ annotation:注解@interface

    ⑥ primitive type:基本数据类型

    ⑦ void

    特别说明:类只有一个,所以反射获取的同一个类,都是一个类(变量会指向同一地址)。数组本身默认的是指向数组第一个数的地址,所以只要数组的元素类型和数组维度(一维数组,二维数组)一样,就是同一个地址。

    exp:

    public class Person{  //本文章中的所有代码都使用这个类

        private String name;

        public int age;

        public Person(String name, int age){

            this.name = name;

            this.age = age;

        }

        private Person(String name) {

            this.name = name;

        }

        public String getName(){

            return name;

        }

        public void setName(String name){

            this.name = name;

        }

        public int getAge(){

            return age;

        }

        public void show(){

            System.out.println("你好,我是08ff");

        }

        private String showNation(){

            System.out.println("我的国籍是"+nation);

             return nation;

        }

    }

    public class ReflectionTest{

        public void test3(){  //获取class实例的方式

            //方式一:调用运行时类的属性:.class。用Class类对象clazz1直接调用类的属性Person.class,获取Person类的结构,泛型不用也可以,但有的地方就需要强转

            Class<Person> clazz1 = Person.class;

            //方式二:通过运行时的类对象,调用getClass()方法

             Person p1 = new Person(); //运行时,已经通过构造器造好了Person类p1对象

            Class clazz2 = p1.getClass(); //通过p1对象,反射找到Person类

            //方式三:通过Class类自己的静态方法:forName(String classPath)    classPath指类的完整名字(包含包)

            Class clazz3 = Class.forName("com.tt.java.Person"); //使用频率最高的方法,最能体现动态性,必须掌握

            //方式四:使用类的静态方法getClassLoader()获取类的加载器:ClassLoader     使用频率最低的方法,了解即可

            ClassLoader classLoader = ReflectionTest.class.getClassLoader();

            Class clazz4 = classLoader.loadClass("com.tt.java.Person");

        }

    //反射之前,对于Person操作

        public void test1(){

            Person p1 = new Person("Tom",12); //1、用构造器创建Person类的对象 

            //2、通过对象,调用其内部的属性、方法

            p1.age=10;

            System.out.println(p1.toString());

            p1.show();

        //在Person类外部,不可以通过Person类的对象,调用其内部的私有结构

        //比如:name、showNation()以及私有构造器

        }

        //反射之后,对于Person操作

        public void test2(){

            Class clazz= Person.class; //反射Person类

            //通过反射,创建Person类对象

            Constuctor cons = clazz.getConstructor(String.class,int.class); //获取Person类构造器。 int.class 反射基本数据类型int,和String一样,也是Class的对象

            Object obj = cons.newInstance("Tom",12);//用反射获取的Person类构造器造对象

            Person p=(Person) obj; //将obj转换成它本身的Person类

          //通过反射,调用对象指定的属性、方法

            Field age = clazz.getDeclaredField("age"); //getDeclaredFields()方法获取当前运行时类中指定变量名的属性

            age.set(p,10);  //设置属性

            Method show = clazz.getDeclaredMethod("show");//通过反射调用show方法,

            show.invoke(p);/*show方法没有形参,所以,直接填对象p就可以了    invoke()调用方法,参数1,方法的调用者(Person类的某个对象),参数2:给方法形参赋值实参*/

           //通过反射,可以调用Person类的私有结构,比如私有构造器、方法、属性(封装性?)

            Constructor cons1 = clazz.getDeclaredConstructor(String.class); 

            cons1.setAccessible(true);  //保证当前属性可访问,否则访问private属性会报错

            Person p1 = (Person) cons1.newInstance("Jerry"); //用反射再实例化一个对象

            //调用私有属性

            Field name = clazz.getDeclaredField("name");

            name.setAccessible(true);  

            name.set(p1,"HanMeimei"); //直接将私有属性name的值修改成HanMeimei

            //调用私有方法

            Method showNation = clazz.getDeclaredMethod("showNation",String.class); 

            showNation.setAccessible(true);

            String nation = (String)showNation.invoke(p1,"中国");//相当于p1.showNation("中国"),nation来接收方法的返回值

            }       

    }

    疑问:反射机制与面向对象中的封装性是不是矛盾的?如何看待这两个技术

    不矛盾。封装性和反射是两回事。封装性主要是告诉你,没必要再去调private的东西,我public的已经把功能做的很好了。反射是,我有能力去调用你的private的东西。

    疑问:通过直接new的方式或反射的方式都可以调用公共的结构,用哪个更好

    答:静态写代码时,直接用new的方式比较好。程序动态运行时,用反射造对象

    3、关于类的加载与ClassLoader的理解

    3.1 类加载器的作用:

    (1)类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.class对象,作为方法区中类数据的访问入口。

    (2)类缓存:标准的JavasE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

    JVM定义了如下类型的类加载器:

    exp:

    public class ClassLoaderTest{

        public void test1(){

            ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();  //对于自定义类ClassLoaderTest,使用系统加载器进行加载

            ClassLoader classLoader1 = classLoader.getParent(); //调用系统加载器的getParent()方法获取扩展类加载器

            ClassLoader classLoader2 = classLoader1.getParent();//调用扩展类加载器的getParent()方法,无法获取引导类加载器,返回null

           //特别说明:引导类加载器主要负责加载java的核心类库,无法加载自定义类

        }

    }

    4、创建运行时类的对象(即用Class对象,创建对应类的对象

    public void test4() throws IllegalAccessException, InstantiationException{ //第一个异常是空参构造器没有权限(private),第二个异常是没有空参构造器

        Class<Person> clazz = Person.class;  //获取Person类,赋值给Class对象 clazz

        //Class类的newInstance()方法,会创建对应的运行时类(这里就是Person)的对象。内部调用了运行时类的空参构造器

        Person obj = clazz.newInstance();//创建Person对象obj。注意如果不用泛型,则返回Object类型,就需要强转 即 = (Person)clazz.newInstance()

    }

    总结:

    (1)要想newInstance()方法正常的创建运行时类的对象,要求:

    ① 运行时类必须提供空参的构造器

    ② 空参的构造器的访间权限得够。通常,设置为public.

    (2)复习:在javabean中要求提供-个public的空参构造器。原因:

    ① 便于通过反射,创建运行时类的对象

    ② 便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

    5、体会反射动态性案例,随机造一个指定类的对象

    public void testN(){

        int num= new Random().nextInt(3);//随机生成0、1、2

        String classPath = " ";

        switch(num){  //根据不同随机数指定要反射的类

            case 0:

                classPath = "java.util.Date"; //反射util.Date

            case 1:

                classPath = "java.sql.Date"; //反射sql.Date   注意:抽到这个会报异常,因为sql.Date没有空参构造器

            case 2:

                classPath = "com.tt.java.Person"; //反射Person

        }

        Object obj = getInstance(classPath); //根据随机数,创建运行时类的对象

    }

        public Object getInstance() throws Exception(){

            Class clazz = Class.forName(classPath);

            return clazz.newInstance();

    }

    5、调用运行时类中指定的结构:属性、方法、构造器

    exp:

    public class ReflectionTest{

        public void testField(){  //调用属性

            Class clazz = Person.class; 

            Person p =(Person)clazz.newInstance();//通过反射创建运行时的Person类对象

            Field name = clazz.getDeclaredField("name"); //getDeclaredField(String fieldName):获取运行类中指定变量名的属性

            name.setAccessible(true); //保证当前属性是可访问的,否则访问private属性会报错

            /*设置当前属性的值

            set(对象名,属性值)  对象名:指明要设置哪个对象的属性。  属性值:将此属性值设置为多少*/

            name.set(p,"Tom");

        }

        public void testMethod(){

            Class clazz = Person.class;

            //创建运行时类的对象

            Person p = (Person) clazz.newInstance();

            /*1、获取指定的某个方法

            getDeclaredMethod():参数1:指明获取的方法的名称  参数2:指明获取的方法形参列表 */

            Method show = clazz.getDeclaredMethod("show",String.class);

            show.setAccessible(true); //2、保证当前属性是可访问的,否则访问private属性会报错

            /*3、调用invoke()方法,参数1,方法的调用者(Person类的某个对象),参数2:给方法形参赋值实参

            invoke()的返回值即为对应类中调用的方法的返回值*/

            Object return Value=show.invoke(p,"CHN");

            Method showDesc = clazz.getDeclaredMethod("showDesc");//加装showDesc()是Person中的static方法

            showDesc.setAccessible(true);

            //如果运行时类没有返回值,invoke()返回null。invoke()第一个参数是Person对象,

            Object returnVal=showDesc.invoke(Person.class);

        }

        public void testConstructor() throws Exception{  //这种用法非常少,还是用反射空参构造器的时候多

            Class clazz = Person.class;

            //1.获取指定的构造器 getDeclaredConstructor():参数:指明构造器的参数列表

            Constructor constructor = clazz.getDeclaredConstructor(String.class)

            //2.保证此构造器是可访问的

            constructor.setAccessible(true);

            //3.调用此构造器创造运行时此类的对象

            Person per = (Person)constructor.niwInstance("Tom");

        }

    }

    6、反射的应用 动态代理  (一个通用代理类动态的去代理所有的被代理类)

    6.1 代理模式的原理  

            使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

            之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能

    6.2 动态代理的原理

    (1)概述        

            动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

    (2)动态代理使用场合:

                   调试

                   远程方法调用

    (3)动态代理相比于静态代理的优点:

          抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

    exp:静态代理举例

    interface ClothFactory {

        void produceCloth();  

    }

    //代理类

    class ProxyClothFactory implements ClothFactory{

        private ClothFactory factory;//用被代理类对象实例化

        public proxyClothFactory(ClothFactory factory){

            this.factory = factory;

        }

        public void produceCloth(){

            System.out.println("代理工厂做一些准备工作");

            factory.produceClooth();

            System.out.println("代理工厂做一些后续的收尾工作");

        }

    }

    class NikeClothFactory implements ClothFactory{

        public void produceCloth(){

            System.out.println("NIke工厂生产一批运动服");

        }    

    }

    main(){

        ClothFactory nike = new NikeClothFactory();//创建被代理类的对象

        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);//创建代理类对象 

        proxyClothFactory.produceCloth();

    }

    //动态代理:/

    interface Human{

        String getBelief();

        void eat(String food);

    }

    //被代理类

    class SuperMan implements Human{

        public String  getBelief(){

            return "I believe I can fly!";

        }

        public void eat(String food){

            System.out.println("我喜欢吃"+ food);

        }

    }

    //代理类

    /问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象

    //问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。

    public class ProxyFactory{  //代理类

        //这个方法的目的是,可以返回一个代理类的对象(返回值Object类)。解决问题一

        public static Object getProxyInstance(Object obj){  //形参obj为想要被代理的类的对象

            MyInvocationHandler handler = new MyInvocationHandler(); //MyInvocationHandler类已实现InvocationHandler接口

            handler.bind(obj);  //handler对象的obj就绑定了代理类

            /*Proxy类的静态方法:static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler invocationHandler ) 这个构造器内部已经通过反射把被代理类的方法都拿到手了,有兴趣可以看源码*/

            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterface(),handler) //前两个形参解决问题一,第三个形参解决问题二

        }

    }

    class MyInvocationHandler implements InvocationHandler{ //实现InvocationHandler接口后,作为Proxy类的第三个参数

        private Object obj; //需要把被代理类的对象进行赋值。

        public void bind(Object obj){

            this.obj = obj;     

        }

       //当我们通过代理类的对象,调用被代理类的方法a时,就会自动调用下面invoke方法

       //因此我们需要将被代理类要执行的方法a的功能声明在invoke()中

        public Object invoke(Object proxy, Method method, Object[ ] args) throws Throwable{ //InvocationHandler接口即重写invoke方法

            //形参proxy就是上面的被代理类的对象obj.getClass().getClassLoader()这个加载器创建的对象,method是代理类代用的方法,

            Object returnValue=method.invoke(obj,args);  //通过代理类的invoke方法,调用被代理对象要调用的方法

            return returnValue;//上述方法的返回值就作为当前类中的invoke的返回值

        }

    }

    main(){

        SuperMan superMan = new SuperMan();

        Human proxyInstance = (Human) ProxyFaceory.getProxyInstance(superMan); //proxyInstance即为已经获取Human类全部方法的代理类对象

        //当通过代理类对象proxyInstance调用方法时,会自动调用被代理类 SuperMan中的同名方法

        proxyInstance.getBelief();//调用上面的invoke()方法,上面的method就是这里的getBelief

        proxyInstance.eat("四川麻辣烫");//也是调用invoke()方法,上面的method就是eat,这时四川麻辣烫,就是被调用参数

    }

    展开全文
  • 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的: 复制代码 代码如下: 原有编码 -> 内部编码 -> 目的编码 python的内部是使用unicode来处理的,但是unicode的使用需要考虑...
  • Go语言排序

    2021-01-23 09:33:24
    1.内部排序:将需要处理的所有数据都加载到内存中进行处理,包括交换式排序、选择式排序和插入式排序 (1)交换排序:冒泡排序、快速排序 2.外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行...
  • 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的: 原有编码 -> 内部编码 -> 目的编码 python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码.....
  • 网站多语言实现分析

    2011-03-14 23:21:00
    1 页面文字的翻译1.1 系统本身自带多语言功能 说明: 很多网站内部都会自带有多语言的功能。可以针对页面的文字在后台翻译成不同的语言,前台用户只需要选择不同的语言按钮,网站页面的文字内容就会变成...
  • python对多国语言的处理是支持的很好的,它可以处理现在任意编码的字符,这里深入的研究... 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的: 原有编码 -> 内部编码 ...
  • Java语言进阶-反射

    2020-06-20 16:52:23
    反射被视为动态语言的关键,反射机制允许程序在执行期间借助反射API获得任何类的内部信息,并能直接操作任意对象的内部属性与方法。 加载完类后,在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个class...
  • 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的: 原有编码 -> 内部编码 -> 目的编码 python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码...
  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 加载完类之后,在堆内存的方法区中就产生了一个Class...
  • 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的:复制代码 代码如下:原有编码 -> 内部编码 -> 目的编码python的内部是使用unicode来处理的,但是unicode的使用需要...
  • @本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 ...有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的: > 原有编码 -> 内部编码 ->
  • Go语言--包(Package)

    2020-12-04 17:25:31
    编程语言借助命名空间来解决标识符不能同名的问题,命名空间实际上相当于给标识符添加了标识前缀,使标识符变得全局唯一。另外,命名空间是程序组织更加模块化,降低了程序内部的耦合性。 一个标识符可以在多个命名...
  • 有一点需要清楚的是,当python要做编码转换的时候,会借助内部的编码,转换过程是这样的:原有编码 -> 内部编码 -> 目的编码python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码格式有两种...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 766
精华内容 306
关键字:

借助内部语言