当前位置: 编程技术>移动开发
本页文章导读:
▪java小技艺临时 java小技巧临时
1.JDK的CLASSPATH设置为%JAVA_HOME%/lib/tools.jar;%JAVA_HOME%/lib/dt.jar2.查看jdk源码 选择外部文件,指向C:\Program Files\Java\jdk1.6.0_20下的src.zip3. eclipse中设置编码 a:windows->Preferences……打.........
▪ (转)首页广告 (转)主页广告
一、布局设置
使用ViewPager来设置主广告,这样既可左右滑动切换
2、滑动切换的时候需要设置一个OnPageChangeListener监听器,当广告切换的时候,利用监听器设置圆点的实心和.........
▪ Objective-C学习札记十:继承二 Objective-C学习笔记十:继承二
接上文 之前定义了矩形类Rectangle,那么我们如果要在桌面上生成这样一个矩形,就需要定位了。为了简便,我们定义桌面的左下角为直角坐标系(.........
[1]java小技艺临时
来源: 互联网 发布时间: 2014-02-18
java小技巧临时
1.JDK的CLASSPATH设置为%JAVA_HOME%/lib/tools.jar;%JAVA_HOME%/lib/dt.jar
2.查看jdk源码
选择外部文件,指向C:\Program Files\Java\jdk1.6.0_20下的src.zip
3. eclipse中设置编码
a:windows->Preferences……打开"首选项"对话框,左侧导航树,导航到general->Workspace,右侧Text file encoding,选择Other,改变为UTF-8,以后新建立工程其属性对话框中的 Text file encoding即为UTF-8.
b:windows->Preferences……打开"首选项"对话框,左侧导航树,导航到general->Content Types,右侧Context Types树,点开Text中每一颗子项,并在中输入"UTF-8",点update!
4.pageEncoding和ContentType 区别
pageEncoding是jsp文件本身的编码
contentType的charset是指服务器 发送给客户端时的内容编码
jsp的显示要经过一下三个阶段,2次编码
第一阶段:将jsp编译成Servlet(.java)文件。用到的指令是pageEncoding,根据pageEncoding=“XXX”的指示,找到编码的规则为“XXX”,服务器在将JSP文件编译成.java文件时会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8编码的JAVA源码(即.java)。
第二阶段:从Servlet文件(.java)到Java字节码文件(.class),从UTF-8到UTF-8。在这一阶段中,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。JAVAC用UTF-8的encoding读取java源码,编译成UTF-8编码的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。这一过程是由JVM的内在规范决定的,不受外界控制。
第三阶段:从服务器到浏览器,这在一过程中用到的指令是contentType。服务器载入和执行由第二阶段生成出来JAVA二进制码,输出的结果,也就是在客户端可见到的结果,在这次输出过程中,由contentType属性中的charset来指定,将UTF8形式的二进制码以charset的编码形式来输出。如果没有人为设定,则默认的是ISO-8859-1的形式。
5.web解决乱码总结
a.开发环境乱码,如打开文件乱码等
jps java等文件编码都设为UTF-8
b.POST请求乱码
由于我们中文浏览器默认会使用ISO-8859-1进行编码数据,所以在浏览器和服务器传输数据间可能会产生乱码。
解决:一:String username=request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
二:再获取参数之前request.setCharacterEncoding("UTF-8"); 最好配置过滤器
c.get提交方式中文乱码问题解决
b类修改只能解决post提交方式的请求,对Get无效。
解决:一:tomcat默认编码ISO-8859-1,改为默认UTF-8即可。修改conf/server.xml,添加URIEncoding=”UTF-8”
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding=”UTF-8”/>
d. JSP HTML页面乱码
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
e. Ajax请求乱码
使用Ajax,JS也是默认使用ISO8859编码,所以在进行请求时遇到中文参数需要进行编码.
如var url = "GetSelectListAction?queryData=subTrade" + "&queryId=" + encodeURI(obj.value) + "&r=" + Math.random();
encodeURI()方法,可以将参数进行转码,默认是转化为UTF-8,如果需要转为其他码制,需要在方法中添加第二个参数。
Math.random(),解决页面缓存问题
f. 连接数据库问题
例如mysql装的时候默认编码是UTF-8,则连接jdbc:mysql://localhost/mydb?useUnicode=true&characterEncoding=utf-8
6 StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能.
7 生成javadoc时,如果提示:编码 GBK 的不可映射字符
eclipse 生成javadoc乱码问题解决
如果源文件编码使用了utf-8编码,那么生成的文档可会有乱码,解决办法如下:
Generate javadoc时, 在第三个对话框的"Extra Javadoc options" 文本框里面加上
-encoding UTF-8 -charset UTF-8
8 final关键字
a、final数据成员,使用前总是被初始化并被强制要求在定义处或构造器中赋值;一旦赋值后,对于基本类型其值会恒定不变,而对于对象引用会始终指向赋值的对象,但指向对象自身是可以修改的;
b、final参数,对于基本类型表示无法改变参数的值,对于对象引用表示无法改变引用所指的对象;
public void addOne(final Other o) { o.i++; } }//这个没问题的,但是如果是:o = new Other(),就错了!
c、final方法,保证方法不会在继承后修改和重载;所有的private方法都隐含式final的;Java中使用动态绑定(后期绑定)实现多态,除了static和final方法是使用前期绑定的;
d、final类,表示该类不可被继承。
9 finally 块区域中的代码虽然在 return 语句之前被执行,但是 finally 块区域中的代码是不能够通过重新赋值的方式来改变 return 语句的返回值。
如下面的方法:执行返回值为11,同时也会输出"进入finally".
public static String test()
{
String result ="11";
try{
System.out.println("GOGO");
return result;
}
finally
{
System.out.println("进入finally");
result = "22";
}
}
10 如果子类自己没有构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;如果子类自己定义了构造方法,则在创建新对象时,它将先执行继承自父类的无参数构造方法,然后再执行自己的构造方法。对于父类含参数的构造方法,子类可以通过在自己的构造方法中使用 super 关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句。
11
String a1 = "abc";
String a2 = new String("abc");
System.out.println(a1==a2); //false
Integer i1 = 134;
Integer i2 = 134;
System.out.println(i1==i2); //false
Integer i5 = 13;
Integer i6 = 13;
System.out.println(i5==i6); //true
Integer i3 = 134;
int i4 = 134;
System.out.println(i3==i4); //true
12 方法重写发生在类继承时,子类可以重写一个父类中已有的方法,必须在返回类型和参数列表一样时才能说是重写,否则就是重载
重写的方法的访问权限不能比被重写的方法的访问权限低
重写的方法不能比被重写的方法抛弃(throws)更多 种类的异常,其抛弃的异常只能少,或者是其子类.另外RuntimeException不需要throws.
13 Java中的标识符是以字符开头,字符包括字母、下划线“_”、美圆符“$”。不能以数字开头,也不能是Java关键字。
14 byte:8位有符号值(-27~+27-1)
char:16位无符号值(0~216-1)
short:16位有符号值(-215~+215-1)
int:32位有符号值(-231~+231-1)
float:32位有符号值(-231~+231-1)
long:64位有符号值(-263~+263-1)
double:64位有符号值
位:bit缩写为b,是存储器的最小单位,可以表示一位二进制数
字节:Byte,缩写为B,由8位组成,是存储器的基本单位,通常被作为一个存储单元
另外还有千字节KB,兆字节MB 吉字节GB 太字节TB ,1KB=1024B
15 float f = 23.9067985表达式是错误的,因为浮点值默认数值是double类型,把他赋给一个float类型的变量会出现编译错误;以下两种形式是对的:float f = 23.9067985F或double f = 23.9067985
1.JDK的CLASSPATH设置为%JAVA_HOME%/lib/tools.jar;%JAVA_HOME%/lib/dt.jar
2.查看jdk源码
选择外部文件,指向C:\Program Files\Java\jdk1.6.0_20下的src.zip
3. eclipse中设置编码
a:windows->Preferences……打开"首选项"对话框,左侧导航树,导航到general->Workspace,右侧Text file encoding,选择Other,改变为UTF-8,以后新建立工程其属性对话框中的 Text file encoding即为UTF-8.
b:windows->Preferences……打开"首选项"对话框,左侧导航树,导航到general->Content Types,右侧Context Types树,点开Text中每一颗子项,并在中输入"UTF-8",点update!
4.pageEncoding和ContentType 区别
pageEncoding是jsp文件本身的编码
contentType的charset是指服务器 发送给客户端时的内容编码
jsp的显示要经过一下三个阶段,2次编码
第一阶段:将jsp编译成Servlet(.java)文件。用到的指令是pageEncoding,根据pageEncoding=“XXX”的指示,找到编码的规则为“XXX”,服务器在将JSP文件编译成.java文件时会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8编码的JAVA源码(即.java)。
第二阶段:从Servlet文件(.java)到Java字节码文件(.class),从UTF-8到UTF-8。在这一阶段中,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。JAVAC用UTF-8的encoding读取java源码,编译成UTF-8编码的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。这一过程是由JVM的内在规范决定的,不受外界控制。
第三阶段:从服务器到浏览器,这在一过程中用到的指令是contentType。服务器载入和执行由第二阶段生成出来JAVA二进制码,输出的结果,也就是在客户端可见到的结果,在这次输出过程中,由contentType属性中的charset来指定,将UTF8形式的二进制码以charset的编码形式来输出。如果没有人为设定,则默认的是ISO-8859-1的形式。
5.web解决乱码总结
a.开发环境乱码,如打开文件乱码等
jps java等文件编码都设为UTF-8
b.POST请求乱码
由于我们中文浏览器默认会使用ISO-8859-1进行编码数据,所以在浏览器和服务器传输数据间可能会产生乱码。
解决:一:String username=request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
二:再获取参数之前request.setCharacterEncoding("UTF-8"); 最好配置过滤器
c.get提交方式中文乱码问题解决
b类修改只能解决post提交方式的请求,对Get无效。
解决:一:tomcat默认编码ISO-8859-1,改为默认UTF-8即可。修改conf/server.xml,添加URIEncoding=”UTF-8”
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding=”UTF-8”/>
d. JSP HTML页面乱码
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
e. Ajax请求乱码
使用Ajax,JS也是默认使用ISO8859编码,所以在进行请求时遇到中文参数需要进行编码.
如var url = "GetSelectListAction?queryData=subTrade" + "&queryId=" + encodeURI(obj.value) + "&r=" + Math.random();
encodeURI()方法,可以将参数进行转码,默认是转化为UTF-8,如果需要转为其他码制,需要在方法中添加第二个参数。
Math.random(),解决页面缓存问题
f. 连接数据库问题
例如mysql装的时候默认编码是UTF-8,则连接jdbc:mysql://localhost/mydb?useUnicode=true&characterEncoding=utf-8
6 StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能.
7 生成javadoc时,如果提示:编码 GBK 的不可映射字符
eclipse 生成javadoc乱码问题解决
如果源文件编码使用了utf-8编码,那么生成的文档可会有乱码,解决办法如下:
Generate javadoc时, 在第三个对话框的"Extra Javadoc options" 文本框里面加上
-encoding UTF-8 -charset UTF-8
8 final关键字
a、final数据成员,使用前总是被初始化并被强制要求在定义处或构造器中赋值;一旦赋值后,对于基本类型其值会恒定不变,而对于对象引用会始终指向赋值的对象,但指向对象自身是可以修改的;
b、final参数,对于基本类型表示无法改变参数的值,对于对象引用表示无法改变引用所指的对象;
public void addOne(final Other o) { o.i++; } }//这个没问题的,但是如果是:o = new Other(),就错了!
c、final方法,保证方法不会在继承后修改和重载;所有的private方法都隐含式final的;Java中使用动态绑定(后期绑定)实现多态,除了static和final方法是使用前期绑定的;
d、final类,表示该类不可被继承。
9 finally 块区域中的代码虽然在 return 语句之前被执行,但是 finally 块区域中的代码是不能够通过重新赋值的方式来改变 return 语句的返回值。
如下面的方法:执行返回值为11,同时也会输出"进入finally".
public static String test()
{
String result ="11";
try{
System.out.println("GOGO");
return result;
}
finally
{
System.out.println("进入finally");
result = "22";
}
}
10 如果子类自己没有构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;如果子类自己定义了构造方法,则在创建新对象时,它将先执行继承自父类的无参数构造方法,然后再执行自己的构造方法。对于父类含参数的构造方法,子类可以通过在自己的构造方法中使用 super 关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句。
11
String a1 = "abc";
String a2 = new String("abc");
System.out.println(a1==a2); //false
Integer i1 = 134;
Integer i2 = 134;
System.out.println(i1==i2); //false
Integer i5 = 13;
Integer i6 = 13;
System.out.println(i5==i6); //true
Integer i3 = 134;
int i4 = 134;
System.out.println(i3==i4); //true
12 方法重写发生在类继承时,子类可以重写一个父类中已有的方法,必须在返回类型和参数列表一样时才能说是重写,否则就是重载
重写的方法的访问权限不能比被重写的方法的访问权限低
重写的方法不能比被重写的方法抛弃(throws)更多 种类的异常,其抛弃的异常只能少,或者是其子类.另外RuntimeException不需要throws.
13 Java中的标识符是以字符开头,字符包括字母、下划线“_”、美圆符“$”。不能以数字开头,也不能是Java关键字。
14 byte:8位有符号值(-27~+27-1)
char:16位无符号值(0~216-1)
short:16位有符号值(-215~+215-1)
int:32位有符号值(-231~+231-1)
float:32位有符号值(-231~+231-1)
long:64位有符号值(-263~+263-1)
double:64位有符号值
位:bit缩写为b,是存储器的最小单位,可以表示一位二进制数
字节:Byte,缩写为B,由8位组成,是存储器的基本单位,通常被作为一个存储单元
另外还有千字节KB,兆字节MB 吉字节GB 太字节TB ,1KB=1024B
15 float f = 23.9067985表达式是错误的,因为浮点值默认数值是double类型,把他赋给一个float类型的变量会出现编译错误;以下两种形式是对的:float f = 23.9067985F或double f = 23.9067985
[2] (转)首页广告
来源: 互联网 发布时间: 2014-02-18
(转)主页广告
一、布局设置
使用ViewPager来设置主广告,这样既可左右滑动切换
2、滑动切换的时候需要设置一个OnPageChangeListener监听器,当广告切换的时候,利用监听器设置圆点的实心和空心。
public void onPageSelected(int position) { currentItem = position; tv_title.setText(titles[position]); //第几个选中的圆点实心 dots.get(oldPosition).setBackgroundResource(R.drawable.dot_normal); dots.get(position).setBackgroundResource(R.drawable.dot_focused); oldPosition = position; }
3、设置pagerAdapter
/** * 填充ViewPager页面的适配器 * * @author Administrator * */ private class MyAdapter extends PagerAdapter { @Override public int getCount() { return imageResId.length; } @Override public Object instantiateItem(View arg0, int arg1) { System.out.println("shilihua..."); ((ViewPager) arg0).addView(imageViews.get(arg1)); return imageViews.get(arg1); } @Override public void destroyItem(View arg0, int arg1, Object arg2) { System.out.println("destroyItem...."); ((ViewPager) arg0).removeView((View) arg2); } @Override //考虑成arg0 为viewPager加载的内容,arg1为instaitateItem返回的View public boolean isViewFromObject(View arg0, Object arg1) { boolean b=arg0 == arg1; System.out.println("check...."+b); return arg0 == arg1; } @Override public void restoreState(Parcelable arg0, ClassLoader arg1) { } @Override public int getItemPosition(Object object) { // TODO Auto-generated method stub //需要刷新用这个? return POSITION_NONE; } @Override public Parcelable saveState() { return null; } /* * 每当页面发生变化的时候startUpdate... instant destory check finishUpdate.. * 参考:http://www.jishuziyuan.com/archive/Kaiewii/7821846.html * */ @Override public void startUpdate(View arg0) { System.out.println("startUpdate"); } @Override public void finishUpdate(View arg0) { System.out.println("finishUpdate"); } } }
4、自动滚动,设置一个定时器
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); // 当Activity显示出来后,每两秒钟切换一次图片显示 scheduledExecutorService.scheduleAtFixedRate(new ScrollTask(), 1, 2, TimeUnit.SECONDS);
/** * 换行切换任务 * * @author Administrator * */ private class ScrollTask implements Runnable { public void run() { synchronized (viewPager) { System.out.println("currentItem: " + currentItem); currentItem = (currentItem + 1) % imageViews.size(); handler.obtainMessage().sendToTarget(); // 通过Handler切换图片 } } }
// 切换当前显示的图片 private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { viewPager.setCurrentItem(currentItem);// 切换当前显示的图片 }; };
[3] Objective-C学习札记十:继承二
来源: 互联网 发布时间: 2014-02-18
Objective-C学习笔记十:继承二
接上文
之前定义了矩形类Rectangle,那么我们如果要在桌面上生成这样一个矩形,就需要定位了。为了简便,我们定义桌面的左下角为直角坐标系(笛卡尔坐标系)的原点,横向向右为X轴正向,竖向向上为Y轴正向。那么我们只要确定了矩形的左下角坐标就可以得到矩形的位置了。此时我们就要引入坐标的概念,那么设计XYPoint类,代码如下:
XYPoint.h文件定义了坐标类XYPoint的接口信息,这里面我们使用整数作为坐标,暂时不考虑小数坐标点。那么提供一个方法来设置坐标点,其实现代码为:
就是给属性x和y进行赋值,没有什么可多说的。因为我们要为矩形设置原点坐标(矩形左下角坐标),那么就需要对矩形类Rectangle进行修改,代码如下:
这是类的接口文件,这里面我们使用了@class指令来指定XYPoint类,@class指令可以为我们指定要使用的类,而不用使用import语句,因为这里我们只需要引入XYPoint的定义而已。如果要引用类的实现部分,那么必须使用import语句,@class就不足以提供所需内容了。同时矩形类加入了两个方法,一个是设置原点origin坐标,一个是获取原点坐标,那么矩形类的实现就修改如下:
我们定义私有属性origin来表示坐标原点,提供了设置方法和获取方法,这就没什么可多说的了,最后来看看主函数,该如何使用它们:
主函数中需要引入两个头文件,因为使用到了它们。创建一个矩形变量和一个坐标变量,对它们赋值后,将坐标原点设置给矩形对象,那么此时矩形对象就拥有了坐标原点,之后我们打印出它们的值,编译运行后得到如下结果:
我们修改一下主函数,代码如下:
这里只是对原点进行了二次赋值,那么编译运行后,我们得到如下结果:
为什么会得到这样的结果?我们并没有显式的再次设置矩形的原点,只是对原点对象重新赋值后,矩形的原点也发生了相应的变化。我们来仔细看一下代码,调用setOrigin方法时,point作为参数传递给该方法,这个值是指针对象,指向了XYPoint对象的内存地址。我们使用rect.origin=point将地址赋值给矩形的原点指针上。因为这样赋值的特性,矩形中的原点和point指向的同一内存空间,那么我们修改了point的值,矩形的origin当然也会跟着改变。那么为了避免这个问题,我们修改setOrigin方法的实现,代码如下:
但是我们却得到了如下错误:
这是因为在Rectangle.h中我们使用@class指令来标识XYPoint,而现在需要XYPoint的细节,那么就需要修改头文件,将@class指令改为#import即可。之后修改主函数如下:
编译运行,得到如下结果:
这样就很合理了,原点就属于矩形自己的,称为它的一个属性了,再次修改坐标点不会对已有原点产生影响。但是问题又产生了,修改主函数如下:
如果我们在这里又定义一个对象来获取矩形的原点,然后对其重新赋值,那么我们得到如下结果:
这是因为我们使用origin方法返回时直接返回矩形内的原点引用,那么对这个引用的修改必然导致了上述的结果。出于这种原因,我们要修改origin方法,使其返回一个对象的副本,从而使得对其的修改不影响原有值:
注意这里返回时重新创建了一个对象,对于这种开销是否必要,还要根据实际情况来定。
在继承中,不能删除和减少方法,但可以通过覆盖来实现对方法的更改,还是前面的示例,定义ClassA和ClassB,代码如下:
类A接口中我们只给出变量定义(为了子类可以使用)和初始化方法,其实现代码如下:
这里我们就是实现initVar方法对变量x进行了简单的赋值。那么来看下ClassB的定义:
它继承自ClassA,并且比类A多了打印变量的方法,其实现代码如下:
代码也很简单,就是对x变量的初始化和打印,那这里也是方法覆盖的体现,那来看测试代码:
编译运行,即可得到如下结果:
那么可以看到这里我们创建了类B,并且调用类B的实现代码对变量进行赋值和打印。从而实现了方法覆盖。如果我们将测试代码改写如下:
显然这里类A是没有printVar方法的,那么会得到如下错误:
因此我们需要修改ClassA的代码,加入printVar方法即可。我们分别创建了类A和类B的对象,它们使用各自的initVar方法后就会初始化自己的x变量,之后再使用各自的printVar方法来打印x的值。clsA和clsB按照各自所属的类选择相应的方法,这就是Objective-C中面向对象的基础。
那么如果我们将printVar方法从ClassB中删除,会是怎样的效果?因为ClassB继承自ClassA,如果ClassA中也未定义printVar方法,显然这里会出现错误。但如果ClassA中定义了printVar方法,那么ClassB就会继承这个方法。运行测试代码,也会打印出200这个值。
继承中还有抽象类的概念,如果一个类的创建只是为了更好的创建子类,那么这个类可以叫做抽象类。这样的类中可以定义实例变量和方法,但是不希望任何人从该类来创建实例,比如NSObject。在这里,只要理解抽象类的含义就可以了。
接下文
接上文
之前定义了矩形类Rectangle,那么我们如果要在桌面上生成这样一个矩形,就需要定位了。为了简便,我们定义桌面的左下角为直角坐标系(笛卡尔坐标系)的原点,横向向右为X轴正向,竖向向上为Y轴正向。那么我们只要确定了矩形的左下角坐标就可以得到矩形的位置了。此时我们就要引入坐标的概念,那么设计XYPoint类,代码如下:
#import <Foundation/Foundation.h> @interface XYPoint : NSObject @property int x,y; -(void) setX:(int)xVal andY:(int) yVal; @end
XYPoint.h文件定义了坐标类XYPoint的接口信息,这里面我们使用整数作为坐标,暂时不考虑小数坐标点。那么提供一个方法来设置坐标点,其实现代码为:
#import "XYPoint.h" @implementation XYPoint @synthesize x,y; -(void) setX:(int)xVal andY:(int)yVal { x=xVal; y=yVal; } @end
就是给属性x和y进行赋值,没有什么可多说的。因为我们要为矩形设置原点坐标(矩形左下角坐标),那么就需要对矩形类Rectangle进行修改,代码如下:
#import <Foundation/Foundation.h> @class XYPoint; @interface Rectangle : NSObject @property int width,height; -(int) area; -(int) perimeter; -(void) setWidth:(int) w andHeight:(int) h; -(XYPoint *) origin; -(void) setOrigin: (XYPoint *) point; @end
这是类的接口文件,这里面我们使用了@class指令来指定XYPoint类,@class指令可以为我们指定要使用的类,而不用使用import语句,因为这里我们只需要引入XYPoint的定义而已。如果要引用类的实现部分,那么必须使用import语句,@class就不足以提供所需内容了。同时矩形类加入了两个方法,一个是设置原点origin坐标,一个是获取原点坐标,那么矩形类的实现就修改如下:
#import "Rectangle.h" @implementation Rectangle { XYPoint *origin; } @synthesize width, height; -(int) area { return width*height; } -(int) perimeter { return (width+height)*2; } -(void) setWidth:(int)w andHeight:(int)h { width=w; height=h; } -(XYPoint *) origin { return origin; } -(void) setOrigin:(XYPoint *)point { origin=point; } @end
我们定义私有属性origin来表示坐标原点,提供了设置方法和获取方法,这就没什么可多说的了,最后来看看主函数,该如何使用它们:
#import "Rectangle.h" #import "XYPoint.h" int main(int argc, const char * argv[]) { @autoreleasepool { Rectangle *rect=[Rectangle new]; XYPoint *point=[XYPoint new]; [point setX:10 andY:23]; [rect setWidth:10 andHeight:23]; rect.origin=point; NSLog(@"Rectangle: width=%i, height=%i",rect.width,rect.height); NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); NSLog(@"Area = %i, Perimeter=%i",rect.area,rect.perimeter); } return 0; }
主函数中需要引入两个头文件,因为使用到了它们。创建一个矩形变量和一个坐标变量,对它们赋值后,将坐标原点设置给矩形对象,那么此时矩形对象就拥有了坐标原点,之后我们打印出它们的值,编译运行后得到如下结果:
我们修改一下主函数,代码如下:
#import "Rectangle.h" #import "XYPoint.h" int main(int argc, const char * argv[]) { @autoreleasepool { Rectangle *rect=[Rectangle new]; XYPoint *point=[XYPoint new]; [point setX:10 andY:23]; [rect setWidth:32 andHeight:36]; rect.origin=point; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); [point setX:23 andY:10]; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); } return 0; }
这里只是对原点进行了二次赋值,那么编译运行后,我们得到如下结果:
为什么会得到这样的结果?我们并没有显式的再次设置矩形的原点,只是对原点对象重新赋值后,矩形的原点也发生了相应的变化。我们来仔细看一下代码,调用setOrigin方法时,point作为参数传递给该方法,这个值是指针对象,指向了XYPoint对象的内存地址。我们使用rect.origin=point将地址赋值给矩形的原点指针上。因为这样赋值的特性,矩形中的原点和point指向的同一内存空间,那么我们修改了point的值,矩形的origin当然也会跟着改变。那么为了避免这个问题,我们修改setOrigin方法的实现,代码如下:
-(void) setOrigin:(XYPoint *) point { if(!origin){ origin=[[XYPoint alloc] init]; } origin.x=point.x; origin.y=point.y; }
但是我们却得到了如下错误:
这是因为在Rectangle.h中我们使用@class指令来标识XYPoint,而现在需要XYPoint的细节,那么就需要修改头文件,将@class指令改为#import即可。之后修改主函数如下:
#import "Rectangle.h" #import "XYPoint.h" int main(int argc, const char * argv[]) { @autoreleasepool { Rectangle *rect=[Rectangle new]; XYPoint *point=[XYPoint new]; [point setX:10 andY:23]; [rect setWidth:32 andHeight:36]; [rect setOrigin:point]; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); [point setX:23 andY:10]; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); } return 0; }
编译运行,得到如下结果:
这样就很合理了,原点就属于矩形自己的,称为它的一个属性了,再次修改坐标点不会对已有原点产生影响。但是问题又产生了,修改主函数如下:
#import "Rectangle.h" #import "XYPoint.h" int main(int argc, const char * argv[]) { @autoreleasepool { Rectangle *rect=[Rectangle new]; XYPoint *point=[XYPoint new]; [point setX:10 andY:23]; [rect setWidth:32 andHeight:36]; [rect setOrigin:point]; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); [point setX:23 andY:10]; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); XYPoint *origin=rect.origin; origin.x=32; origin.y=36; NSLog(@"Origin at (%i, %i)",rect.origin.x,rect.origin.y); } return 0; }
如果我们在这里又定义一个对象来获取矩形的原点,然后对其重新赋值,那么我们得到如下结果:
这是因为我们使用origin方法返回时直接返回矩形内的原点引用,那么对这个引用的修改必然导致了上述的结果。出于这种原因,我们要修改origin方法,使其返回一个对象的副本,从而使得对其的修改不影响原有值:
-(XYPoint *) origin { XYPoint *point=[XYPoint new]; point.x=origin.x; point.y=origin.y; return point; }
注意这里返回时重新创建了一个对象,对于这种开销是否必要,还要根据实际情况来定。
在继承中,不能删除和减少方法,但可以通过覆盖来实现对方法的更改,还是前面的示例,定义ClassA和ClassB,代码如下:
#import <Foundation/Foundation.h> @interface ClassA : NSObject { int x; } -(void) initVar; @end
类A接口中我们只给出变量定义(为了子类可以使用)和初始化方法,其实现代码如下:
#import "ClassA.h" @implementation ClassA -(void) initVar { x=100; } @end
这里我们就是实现initVar方法对变量x进行了简单的赋值。那么来看下ClassB的定义:
#import "ClassA.h" @interface ClassB : ClassA -(void) initVar; -(void) printVar; @end
它继承自ClassA,并且比类A多了打印变量的方法,其实现代码如下:
#import "ClassB.h" @implementation ClassB -(void) initVar { x=200; } -(void) printVar { NSLog(@"x = %i",x); } @end
代码也很简单,就是对x变量的初始化和打印,那这里也是方法覆盖的体现,那来看测试代码:
#import "ClassB.h" int main(int argc, const char * argv[]) { @autoreleasepool { ClassB *clsB=[ClassB new]; [clsB initVar]; [clsB printVar]; } return 0; }
编译运行,即可得到如下结果:
那么可以看到这里我们创建了类B,并且调用类B的实现代码对变量进行赋值和打印。从而实现了方法覆盖。如果我们将测试代码改写如下:
#import "ClassB.h" int main(int argc, const char * argv[]) { @autoreleasepool { ClassA *clsA=[ClassA new]; ClassB *clsB=[ClassB new]; [clsA initVar]; [clsA printVar]; [clsB initVar]; [clsB printVar]; } return 0; }
显然这里类A是没有printVar方法的,那么会得到如下错误:
因此我们需要修改ClassA的代码,加入printVar方法即可。我们分别创建了类A和类B的对象,它们使用各自的initVar方法后就会初始化自己的x变量,之后再使用各自的printVar方法来打印x的值。clsA和clsB按照各自所属的类选择相应的方法,这就是Objective-C中面向对象的基础。
那么如果我们将printVar方法从ClassB中删除,会是怎样的效果?因为ClassB继承自ClassA,如果ClassA中也未定义printVar方法,显然这里会出现错误。但如果ClassA中定义了printVar方法,那么ClassB就会继承这个方法。运行测试代码,也会打印出200这个值。
继承中还有抽象类的概念,如果一个类的创建只是为了更好的创建子类,那么这个类可以叫做抽象类。这样的类中可以定义实例变量和方法,但是不希望任何人从该类来创建实例,比如NSObject。在这里,只要理解抽象类的含义就可以了。
接下文
最新技术文章: