1>> 下载struts2所需要的jar文件
http://struts.apache.org
首页上就可以直接点击下载需要的最新版本。
Tomcat 删除掉。
2>>添加struts2的配置文件 struts.xml ---dtd-->核心的jar文件中 可以找到 dtd文件
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
3>>在web.xml文件中 添加启动struts2 MVC框架的过滤器
加载struts2的配置文件 面试题
struts-default.xml
struts-plugin.xml
struts.xml
struts.properties
web.xml
注意:如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值.
状态控制
和其他编程语言一样,TorqueScript支持分支结构.
if, then, elseif(<boolean expression>) { pass logic } else { alternative logic } // 控制灯光的全局变量 $lightsShouldBeOn = true; // 检查灯是否应该打开 if($lightsShouldBeOn) { // 开灯 turnOnLights(); echo("Lights have been turned on"); } else { // 关灯 turnOffLights(); echo("Lights have been turned off"); }
// 控制灯光的全局变量 $lightsShouldBeOn = true; // 检查灯是否应该打开 if($lightsShouldBeOn) turnOnLights(); //开灯 else turnOffLights(); // 关灯
If your code is using several cascading if-then-else statements based on a single value, you might want to use a switch statement instead. Switch statements are easier to manage and read. There are two types of switch statements, based on data type: numeric (switch) and string (switch$).
TorqueScript支持两种多分支结构
1: switch: 数字类型
switch(<numeric expression>) { case value0: statements; case value1: statements; case value3: statements; default: statements; }
PS: 没有break;
switch($ammoCount) { case 0: echo("Out of ammo, time to reload"); reloadWeapon(); case 1: echo("Almost out of ammo, warn user"); lowAmmoWarning(); case 100: echo("Full ammo count"); playFullAmmoSound(); default: doNothing(); }
2: switch$: 字符串类型
switch$ (<string expression>) { case "string value 0": statements; case "string value 1": statements; ... case "string value N": statements; default: statements; }
// Print out specialties switch($userName) { case "Heather": echo("Sniper"); case "Nikki": echo("Demolition"); case "Mich": echo("Meat shield"); default: echo("Unknown user"); }
循环
和C++一样,Torquescript支持两种循环,分别如下:
For循环for(expression0; expression1; expression2) { statement(s); }
for(%count = 0; %count < 3; %count++) { echo(%count); } OUTPUT: 0 1 2
语法:
while(expression) { statements; }
%countLimit = 0; while(%countLimit <= 5) { echo("Still in loop"); %count++; } echo("Loop was terminated");
Much of your TorqueScript experience will come down to calling existing functions and writing your own. Functions are a blocks of code that only execute when you call them by name. Basic functions in TorqueScript are defined as follows:
归根结底,Torquescript的代码大多都是要调用存在的引擎函数方法和自定义方法.函数方法是一个在需要时主动调用函数名才执行的代码块.
基本的脚本函数定义方式如下:
// function - 脚本函数的关键字 // function_name - 函数名 // arg0-N... - 参数表(任意个) // statements - 函数逻辑 // return val - 返回值 function function_name([arg0],...,[argn]) { statements; [return val;] }
例子:
function echoRepeat (%echoString, %repeatCount) { for (%count = 0; %count < %repeatCount; %count++) { echo(%echoString); } }
echoRepeat("hello!", 5); OUTPUT: "hello!" "hello!" "hello!" "hello!" "hello!"
如果定义了一个函数名已经存在的方法,Torquescript将覆盖老的函数.即使只是参数数量不同,老的方法仍然会给覆盖.
比如:
function OutputA( %text ) { echo( %text ); } function OutputA( %text, %addon ) { echo( %text SPC "+" SPC %addon ); } 调用: OutputA( "A output function" ); OutputA( "A output function", "AddOn Infomation" ); 输出: A output function + A output function + AddOn Infomation
Console Functions:
控制台全局方法,是C++函数导出到TorqueScript中使用,是全局函数,比如使用到的echo.
Objects:
对象,用在脚本需要处理游戏对象的复杂情况.需要记住的一点就是在Torquescript中的所有的一切都是一个字符串,但是当需要访问一个精灵,场景对象或者任意一个其他对象,字符串就需要转换为相应的对象ID.
对象的定义语法:
// In TorqueScript %objectID = new ObjectType(Name) { [existing_field0 = InitialValue0;] ... [existing_fieldN = InitialValueN;] [dynamic_field0 = InitialValue0;] ... [dynamic_fieldN = InitialValueN;] };
语法解释:
%objectID - 保存对象句柄的变量,new是一个关键字,他告诉引擎创建一个ObjectType指定的对象实例.
ObjectType - 引擎或者脚本中的定义的任意一个SimObject的继承类或者子类.SimObject的继承对象统称为游戏世界对象.
Name (可选项) - 对象名字符串
existing_fieldN - 初始化已经存在的类成员变量,当然变量必须是导出到脚本的变量.
dynamic_fieldN - 最后是添加一些新的变量,这些变量有唯一性,只属于这里实例化的对象,被称为动态变量.
Handles vs Names 每一个游戏对象都可以通过两个参数来访问,他们分别是:
Handle - 当对象创建时分配的全局唯一的数字ID编号.
Name - 在对象创建时可选的指定对象名.
例子:
// In this example, Truck is the name of the object new SceneObject(Truck) { position = "0 0"; size = "5 5"; };
Methods 除了创建独立的全局方法之外,Torquescript还允许创建和调用绑定对象的方法(类似于类成员函数).一些重要的控制方法是用C++写好然后导出到脚本中,随时可以使用,要使用这些方法只需要通过(.)符号.
语法:
objHandle.function_name(); objName.function_name();
new SceneObject(Truck) { position = "0 0"; size = "5 5"; }; // 将Truck对象的所有导出方法输出打印到控制台日志. Truck.dump(); // 获取对象的数字ID编号 $objID = Truck.getID(); // 输出ID echo("Object ID: ", $objID); // 获取对象的位置 %position = $objID.getPosition(); // 输出位置 echo("Object Position: ", %position);
上面的代码展示了如何通过对象句柄和对象名来调用对象的方法.另外,Torquescript还支持对象脚本辅助函数的创建.
语法:
// function - 函数定义关键字 // ClassName::- 类名 // function_name - 函数名 // ... - 参数表 // statements - 逻辑代码 // %this- 传递调用对象的句柄参数 // return val - 返回值 function Classname::func_name(%this, [arg0],...,[argn]) { statements; [return val;] }
最低要求,控制台成员方法需要传递一个对象的句柄.你将经常看到第一个参数是%this.
人们用this作为提醒,但是你可以随意的命名.
一个简单的例子,输出一个由Player类继承而来的对象,名字叫Samurai,很可能会有一些特殊的造型和玩法给予这个武士对象,所以增加自定义的新方法,如下:
// 武士刀入鞘 function Samurai::sheatheSword(%this) { echo("Katana sheathed"); }
当创建了一个武士对象,将会获得一个对象ID,假设这个ID为1042,那么我们可以通过调用上面的方法完成入鞘的操作:
1042.sheatheSword(); OUTPUT: "Katana sheathed"
这里需要注意,我们并没有传递任何参数给函数,%this参数是默认的,由引擎内部自动传递,不需要我们进行额外的传递.
学了那么久的Objective-C,给我的感觉就是它什么都是动态的,你将会听到一个新的名词:
一、动态方法解析
1、+(BOOL) resolveInstanceMethod:(SEL) sel
这是NSObject根类提供的类方法,调用时机为当被调用的方法实现部分没有找到,而消息转发机制启动之前的这个中间时刻。
2、@dynamic关键字
Objective-C2.0 提供了@dynamic关键字,从名字上可以看出来,它一定是跟动态相关的。猜对了,这个关键字告诉编译器,某个属性的实现是动态的。如果我们在@interface接口文件中声明了一个属性,如下所示:
@property(nonatomic,retain) NSString *name;在@implementation文件中做了如下声明:
@dynamic name;就表示编译器须动态地生成该属性对应的方法。如果想将该属性的-(void)setName:(NSString *)name方法用dynamicMethodIMP函数来代替,可以这样做:
void dynamicMethodIMP(id self, SEL _cmd) { // implementation .... } + (BOOL)resolveInstanceMethod:(SEL)sel { NSLog(@"sel is %@", NSStringFromSelector(sel)); if(sel == @selector(setName:)){ class_addMethod([self class],sel,(IMP)dynamicMethodIMP,"v@:"); return YES; } return [super resolveInstanceMethod:sel]; }在resolveInstanceMethod的实现中,我们通过class_addMethod方法动态的向当前对象增加了dynamicMethodIMP函数,来代替-(void)setName:(NSString *)name的实现部分,从而达到了动态生成name属性方法的目的。
值得说明的是:
①在我看来,@dynamic关键字的作用并非想象中的那么大,理由是,如果没有在@implementation文件中做出@dynamic声明,而在resolveInstanceMethod方法中做了方法重定向的工作,一样能顺利的调用dynamicMethodIMP函数。唯一的不同之处在于进行了@dynamic声明时,编译器不会告警而已!!
②在上个例子中,我们自己实现了-(void)setName:(NSString *)name方法,则在运行的时候,调用完我们实现的-(void)setName:(NSString *)name方法后,运行时系统仍然会调+(BOOL) resolveInstanceMethod:(SEL) sel方法,只不过这里的sel会变成_doZombieMe,从而我们实现重定向的if分支就进不去了。
③"v@:"属于Objective-C类型编码的内容,感兴趣的同学可以自己google一下。
二、runtime system消息转发机制
对象是谦恭的,它会接收所有发送过来的消息,哪怕这些消息自己无法响应。问题来了:当对象无法响应这些消息时怎么办?runtime提供了消息转发机制来处理该问题。
当外部调用的某个方法对象没有实现,而且resolveInstanceMethod方法中也没有做重定向处理时,就会触发- (void)forwardInvocation:(NSInvocation *)anInvocation方法。在该方法中,可以实现对不能处理的消息做的一些默认处理,也可以以其它的某种方式来避免错误被抛出。像forwardInvocation:的名字一样,这个方法通常用来将不能处理的消息转发给其它的对象。通常我们重写该方法的方式如下所示:
-(void)forwardInvocation:(NSInvocation *)invocation { SEL invSEL = invocation.selector; if ([someOtherObject respondsToSelector:invSEL]) [anInvocation invokeWithTarget:someOtherObject]; } else { [self doesNotRecognizeSelector:invSEL]; } }
怎么看着有点像多继承呀???你说对了,消息转发提供了多重继承的很多特性。然而,两者有很大的不同:多重继承是将不同的行为封装到单个的对象中,有可能导致庞大的,复杂的对象。而消息转发是将问题分解到更小的对象中,但是又以一种对消息发送对象来说完全透明的方式将这些对象联系起来。总之,Objective-C通过这种方式,一定程度上减小了自己不支持多继承的劣势。
经过半个月的时间,自己总结、整理出了这三篇文章,到这里,对Objective-C运行时的学习算是告一段落了。文笔的原因,文章结构不是很清晰,还请见谅。对运行时理解不到位,或者是有错误的地方,还请广大博友指出,感激不尽!