[url=http://jb51.net/article/36864.htm]深入C#字符串和享元(Flyweight)模式的使用分析
[/url][/b] 字符串的反转输出
这种情况下,一般会将字符串看做是字符数组,然后利用反转数组的方式来反转字符串。
眼花缭乱的方法调用
[b]有继承关系结构中的方法调用
[/b] 继承是面向对象设计中的常见方式,它可以有效的实现”代码复用“,同时子类也有重写父类方法的自由,这就对到底是调用父类方法还是子类方法带来了麻烦。
来看下面的代码:
public class PropertyTest {
public static void main(String[] args)
{
ParentDef v1 = new ParentDef();
ParentDef v2 = new ChildDef();
ChildDef v3 = new ChildDef();
System.out.println("=====v1=====");
System.out.println("staticValue:" + v1.staticValue);
System.out.println("value:" + v1.value);
System.out.println("=====v2=====");
System.out.println("staticValue:" + v2.staticValue);
System.out.println("value:" + v2.value);
System.out.println("=====v3=====");
System.out.println("staticValue:" + v3.staticValue);
System.out.println("value:" + v3.value);
}
}
class ParentDef
{
public static final String staticValue = "父类静态变量";
public String value = "父类实例变量";
}
class ChildDef extends ParentDef
{
public static final String staticValue = "子类静态变量";
public String value = "子类实例变量";
}
输出结果如下:
=====v1=====
staticValue:父类静态变量
value:父类实例变量
=====v2=====
staticValue:父类静态变量
value:父类实例变量
=====v3=====
staticValue:子类静态变量
value:子类实例变量
[b]结论
[/b] 对于调用父类方法还是子类方法,只与变量的声明类型有关系,与实例化的类型没有关系。
[b]到底是值传递还是引用传递
[/b] 对于这个话题,我的观点是值传递,因为传递的都是存储在栈中的内容,无论是基本类型的值,还是指向堆中对象的指针,都是值而非引用。并且在值传递的过程中,JVM会将值复制一份,然后将复制后的值传递给调用方法。
[b]按照这种方式,我们来看下面的代码:
[/b]
public class ParamTest {
public void change(int value)
{
value = 10;
}
public void change(Value value)
{
Value temp = new Value();
temp.value = 10;
value = temp;
}
public void add(int value)
{
value += 10;
}
public void add(Value value)
{
value.value += 10;
}
public static void main(String[] args)
{
ParamTest test = new ParamTest();
Value value = new Value();
int v = 0;
System.out.println("v:" + v);
System.out.println("value.value:" + value.value);
System.out.println("=====change=====");
test.change(v);
test.change(value);
System.out.println("v:" + v);
System.out.println("value.value:" + value.value);
value = new Value();
v = 0;
System.out.println("=====add=====");
test.add(v);
test.add(value);
System.out.println("v:" + v);
System.out.println("value.value:" + value.value);
}
}
class Value
{
public int value;
}
它的输出结果:
v:0
value.value:0
=====change=====
v:0
value.value:0
=====add=====
v:0
value.value:10
我们看到,在调用change方法时,即使我们传递进去的是指向对象的指针,但最终对象的属性也没有变,这是因为在change方法体内,我们新建了一个对象,然后将”复制过的指向原对象的指针“指向了“新对象”,并且对新对象的属性进行了调整。但是“复制前的指向原对象的指针”依然是指向“原对象”,并且属性没有任何变化。
[b]final/finally/finalize的区别
[/b] final可以修饰类、成员变量、方法以及方法参数。使用final修饰的类是不可以被继承的,使用final修饰的方法是不可以被重写的,使用final修饰的变量,只能被赋值一次。
[b]使用final声明变量的赋值时机:[/b]
1)定义声明时赋值
2)初始化块或静态初始化块中
3)构造函数
来看下面的代码:
class FinalTest
{
public static final String staticValue1 = "静态变量1";
public static final String staticValue2;
static
{
staticValue2 = "静态变量2";
}
public final String value1 = "实例变量1";
public final String value2;
public final String value3;
{
value2 = "实例变量2";
}
public FinalTest()
{
value3 = "实例变量3";
}
}
[b]finally一般是和try...catch放在一起使用,主要用来释放一些资源。[/b]
我们来看下面的代码:
public class FinallyTest {
public static void main(String[] args)
{
finallyTest1();
finallyTest2();
finallyTest3();
}
private static String finallyTest1()
{
try
{
throw new RuntimeException();
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("Finally语句被执行");
}
try
{
System.out.println("Hello World");
return "Hello World";
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("Finally语句被执行");
}
return null;
}
private static void finallyTest2()
{
int i = 0;
for (i = 0; i < 3; i++)
{
try
{
if (i == 2) break;
System.out.println(i);
}
finally
{
System.out.println("Finally语句被执行");
}
}
}
private static Test finallyTest3()
{
try
{
return new Test();
}
finally
{
System.out.println("Finally语句被执行");
}
}
}
执行结果如下:
java.lang.RuntimeException
at sample.interview.FinallyTest.finallyTest1(FinallyTest.java:16)
at sample.interview.FinallyTest.main(FinallyTest.java:7)
Finally语句被执行
Hello World
Finally语句被执行
Finally语句被执行
Finally语句被执行
Finally语句被执行
Test实例被创建
Finally语句被执行
注意在循环的过程中,对于某一次循环,即使调用了break或者continue,finally也会执行。
finalize则主要用于释放资源,在调用GC方法时,该方法就会被调用。
[b]来看下面的示例:
[/b]
class FinalizeTest
{
protected void finalize()
{
System.out.println("finalize方法被调用");
}
public static void main(String[] args)
{
FinalizeTest test = new FinalizeTest();
test = null;
Runtime.getRuntime().gc();
}
}
执行结果如下:
[b]finalize方法被调用
[/b]
[b]关于基本类型的一些事儿
[/b] 基本类型供分为9种,包括byte/short/int/long/float/double/boolean/void,每种基本类型都对应一个“包装类”,其他一些基本信息如下:
. 基本类型:byte 二进制位数:8
. 包装类:java.lang.Byte
. 最小值:Byte.MIN_VALUE=-128
. 最大值:Byte.MAX_VALUE=127
. 基本类型:short 二进制位数:16
. 包装类:java.lang.Short
. 最小值:Short.MIN_VALUE=-32768
. 最大值:Short.MAX_VALUE=32767
. 基本类型:int 二进制位数:32
. 包装类:java.lang.Integer
. 最小值:Integer.MIN_VALUE=-2147483648
. 最大值:Integer.MAX_VALUE=2147483647
. 基本类型:long 二进制位数:64
. 包装类:java.lang.Long
. 最小值:Long.MIN_VALUE=-9223372036854775808
. 最大值:Long.MAX_VALUE=9223372036854775807
. 基本类型:float 二进制位数:32
. 包装类:java.lang.Float
. 最小值:Float.MIN_VALUE=1.4E-45
. 最大值:Float.MAX_VALUE=3.4028235E38
. 基本类型:double 二进制位数:64
. 包装类:java.lang.Double
. 最小值:Double.MIN_VALUE=4.9E-324
. 最大值:Double.MAX_VALUE=1.7976931348623157E308
. 基本类型:char 二进制位数:16
. 包装类:java.lang.Character
. 最小值:Character.MIN_VALUE=0
. 最大值:Character.MAX_VALUE=65535
[b]关于基本类型的一些结论(来自《Java面试解惑》)
[/b]•未带有字符后缀标识的整数默认为int类型;未带有字符后缀标识的浮点数默认为double类型。
•如果一个整数的值超出了int类型能够表示的范围,则必须增加后缀“L”(不区分大小写,建议用大写,因为小写的L与阿拉伯数字1很容易混淆),表示为long型。
•带有“F”(不区分大小写)后缀的整数和浮点数都是float类型的;带有“D”(不区分大小写)后缀的整数和浮点数都是double类型的。
•编译器会在编译期对byte、short、int、long、float、double、char型变量的值进行检查,如果超出了它们的取值范围就会报错。
•int型值可以赋给所有数值类型的变量;long型值可以赋给long、float、double类型的变量;float型值可以赋给float、double类型的变量;double型值只能赋给double类型变量。
[b]关于基本类型之间的转换
[/b] 下面的转换是无损精度的转换:
•byte->short
•short->int
•char->int
•int->long
•float->double
[b]下面的转换是会损失精度的:[/b]
•int->float
•long->float
•long->double
除此之外的转换,是非法的。
[b]和日期相关的一些事儿
[/b] Java中,有两个类和日期相关,一个是Date,一个是Calendar。我们来看下面的示例:
public class DateTest {
public static void main(String[] args) throws ParseException
{
test1();
test2();
test3();
}
private static void test1() throws ParseException
{
Date date = new Date();
System.out.println(date);
DateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sf.format(date));
String formatString = "2013-05-12";
System.out.println(sf.parse(formatString));
}
private static void test2()
{
Date date = new Date();
System.out.println("Year:" + date.getYear());
System.out.println("Month:" + date.getMonth());
System.out.println("Day:" + date.getDate());
System.out.println("Hour:" + date.getHours());
System.out.println("Minute:" + date.getMinutes());
System.out.println("Second:" + date.getSeconds());
System.out.println("DayOfWeek:" + date.getDay());
}
private static void test3()
{
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
System.out.println(c.getTimeZone());
System.out.println("Year:" + c.get(Calendar.YEAR));
System.out.println("Month:" + c.get(Calendar.MONTH));
System.out.println("Day:" + c.get(Calendar.DATE));
System.out.println("Hour:" + c.get(Calendar.HOUR));
System.out.println("HourOfDay:" + c.get(Calendar.HOUR_OF_DAY));
System.out.println("Minute:" + c.get(Calendar.MINUTE));
System.out.println("Second:" + c.get(Calendar.SECOND));
System.out.println("DayOfWeek:" + c.get(Calendar.DAY_OF_WEEK));
System.out.println("DayOfMonth:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("DayOfYear:" + c.get(Calendar.DAY_OF_YEAR));
}
}
输出结果如下:
Sat May 11 13:44:34 CST 2013
-05-11
Sun May 12 00:00:00 CST 2013
Year:113
Month:4
Day:11
Hour:13
Minute:44
Second:35
DayOfWeek:6
Sat May 11 13:44:35 CST 2013
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
Year:2013
Month:4
Day:11
Hour:1
HourOfDay:13
Minute:44
Second:35
DayOfWeek:7
DayOfMonth:11
DayOfYear:131
需要注意的是,Date中的getxxx方法已经变成deprecated了,因此我们尽量使用calendar.get方法来获取日期的细节信息。
另外,注意DateFormat,它不仅可以对日期的输出进行格式化,而且可以逆向操作,将符合Format的字符串转换为日期类型。