(原创) 脚踏实地学Java之:基础篇 最近与几个朋友闲聊技术,当谈起他们各自用JAVA做项目时所用到的技术时,夸夸其谈,不知所云,犹如布什总统竞选前的演讲一般精彩,听的我是云里雾里,一头雾水!但当我问他们一些基础JAVA语言机制,与面向对象的一些基本思想时,回答起来却吞吞吐吐与刚才“演讲”时的表情却荡然不在!我就纳闷了“谈话前后时间不超过十分钟,这差距咋就这么大呢!!哈哈!!!”。 好了,不闲扯了,谈正题吧。上边说了这么多,意思就是,学习就要跟做人做事一样,脚踏实地,一步一个脚印,在学习技术的路上容不得半点虚假,也没有所谓的捷径可走,如果你走了弯路,相信你总有一天还是再要走会来的。这就是我写这篇文章的目的,帮助那些正在学习或用JAVA做开发的人员掌握技术细节,打好基础。 注:本系列前几篇文章使用实例来讲解一些基础概念,以后的章节里会不断对JAVA机制深入。如果您是工作了几年的高手就帮我挑挑错,不胜感激!!!如果您是初学JAVA者,我建议你把我做的实例用你的理解重现一便,如果有技术问题可以共同探讨。我的邮箱地址:[email protected]
(1) equals 与 == 的比较 (公认为在java界面试时最常问到的问题): primitive类型存储在栈中,它不是对象类型,所以primitive 类型中也就不可能包含equals方法。对于基本类型,没有向对象中发送消息的说法,自然也不会有方法成员的存在。
1) 使用 “==”来比较两个基本(primitive)类型值是否相等:
/*----------------------------------------------------------------------------------------------*/ public class TestEquals { public static void main(String[] args) { int i = 5,j = 3; System.out.println ( i == j ? "the object equals !!": "the object unequals!!!!!!!!!!!!"); } } /*----------------------------------------------------------------------------------------------*/ RESULT: the object unequals!!!!!!!!!!!! 相反,如果两个变量的值相等,则输出为the object equals !!
2) 使用“==”来比较两个对象引用是否相等:
/*----------------------------------------------------------------------------------------------*/ class Cup {} public class ObjectCompare { public static void main(String[] args) { Cup cup1 = new Cup(); Cup cup2 = new Cup(); System.out.println (cup1 == cup2 ? "The object reference equals" : "The object reference unequals"); } } /*----------------------------------------------------------------------------------------------*/ RESULT : The object reference unequals
3) 使用equals方法(java 中所有对象共有方法)来比较两个对象(逻辑上)是否一致:
/*----------------------------------------------------------------------------------------------*/ class a { int i = 5; public boolean equals(final Object object) { return (((b)object).i==i); } } class b { int i = 5; public boolean equals(final Object object) { return(((a)object).i==i); } } public class TestEqua { public static void main(String args[]) { a a = new a(); b b = new b(); System.out.println ( b.equals(a) ? "equals!!!!!!!!!!" : "unequals"); } } /*----------------------------------------------------------------------------------------------*/
RESULT : equals!!!!!!!!!! 这两个对象相等的方法是自定义的(只要两个对象中的变量i的值相等,则它们就是相等的),就是说,相等的条件是由用户根据具体的业务需求来定义的。
(2)接口与继承类:
接口(interface): 接口定义了实现它的子类的类型形式,其中包括方法的名称、方法的返回值、参数列表,JAVA不支持多重继承,要实现象C++中类多重继承的功能,就用到了接口(因为你可以实现多个接口,接口又同时可以继承接口,当然了,还有别的方法实现多重继承,在以后的文章会逐一介绍)。曾有这样的说法,面向对象的编程就是面向接口的编程,这句话足以说明接口在面向对象的概念里的重要位置,关于interface的更深入内容我会在今后的文章里详细讲解,,在这里只是用到了接口的概念所以进行了简单介绍。
继承(extends): 如果一个类从另一个继承,你就可以说:这个类就是被继承的那个类,通常被继承的类叫做超类(superClas),而继承类叫做子类(subClass),与此同时子类可以拓展与覆写超类的方法与属性。 类TestInterOrExtends 实现了接口b与抽象类a,接口与抽象类里都定义了event方法,在TestInterOrExtends 里不会冲突。
/*----------------------------------------------------------------------------------------------*/ abstract class A { public void event() { System.out.println ("The abstract class event method!!!!!!!!!!!!!!"); } } interface B { public void event(); } public class TestInterOrExtends extends A implements B { public void event() { System.out.println ("The event of extend!!!!!!!!!!!!!!!!!!"); } public static void main(String agrs[]) { new TestInterOrExtends().event(); } } /*----------------------------------------------------------------------------------------------*/ The result : The event of extend!!!!!!!!!!!!!!!!!!
(3)类的调用顺序: 子类总是优先调用父类默认的构造函数,调用的顺序也就是按照继承的顺序线形排列。
/*----------------------------------------------------------------------------------------------*/ class A { public A() { System.out.println ("The Constructor of a "); } } public class TestInterOrExtends extends A {
public TestInterOrExtends() { System.out.println ("The Constructor of TestInterOrExtends"); } public static void main(String agrs[]) { new TestInterOrExtends(); } } /*----------------------------------------------------------------------------------------------*/ The result : The Constructor of a The Constructor of TestInterOrExtends 关于调用顺序的说明,前几天在论坛上看见一个经典的例子与大家共享: /*----------------------------------------------------------------------------------------------*/ public class Test2 extends Test1{ { System.out.print("1"); } Test2(){ System.out.print("2"); } static{ System.out.print("3"); } { System.out.print("4"); } public static void main(String[] args) { new Test2(); } } class Test1 { Test1(){ System.out.print("5"); } static{ System.out.print("6"); } } /*----------------------------------------------------------------------------------------------*/ RESULT : 635142
(4)接口里的成员必须全部是public的,如果不写public则默认是public的,如过将接口内的成员函数或方法声明为private or protected的 则编译器将会在编译时产生错误,如果在接口里声明了变量,则它们就是static 和 final的。
/*----------------------------------------------------------------------------------------------*/ interface aaa { protected void a(); public void b(); } class bb implements aaa { public void a() { System.out.println ("The implemention aaa of bb"); } public void b() { System.out.println ("The implemention aaa of bb's method"); } } public class TestMyInter { public static void main(String[] args) { aaa a = new bb(); a.a(); } } /*----------------------------------------------------------------------------------------------*/ result : --------------------Configuration: JDK version <Default>-------------------- F:\homeWork\JAVA\TestMyInter.java:3: modifier protected not allowed here protected void a(); ^ 1 error
<5> 类型转换: 下传(downCasting)是不安全的如 : /*----------------------------------------------------------------------------------------------*/ class a { public void mm() { System.out.println ("MMZHANG"); } } class b extends a { } public class DownCasting { public static void main(String[] args) { try { b b = new b(); a a = new a(); ((b)a).mm(); } catch(Exception ex) { ex.printStackTrace(); } } } /*----------------------------------------------------------------------------------------------*/
这种将父类转换为子类可以通过编译,但会在run time 时产生异常: Run time Result : java.lang.ClassCastException at DownCasting.main(DownCasting.java:19) 如果将类的转换变为上传(upCasting)则是安全的,因为父类具有子类的所有属性方法,而子类不仅包含了父类的方法属性而且具有自身拓展的属性及方法,而拓展的这些方法在父类里并没有体现。所以,上传是安全的。
<6> Class.forName(String); 使用类名字符串作为参数,返回Class的Reference,但事实上在程序里并没有用到这个Reference. Note : Must be caught exception /*----------------------------------------------------------------------------------------------*/ class aa { static { System.out.println ("The static method aa"); } } class bb { } public class ClassForName { public static void main(String[] args) { try { Class.forName("aa"); } catch(ClassNotFoundException ex) { System.out.println ("The class not found "); } } } /*----------------------------------------------------------------------------------------------*/
<7> Java编程语言只由值传递参数!!!C++转Java的程序员容易对这一点混淆(C++有引用类型)。 当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用(就是说,当你向一个方法传递参数时,传递给方法的参数就是该对象引用的副本)。 For example : /*----------------------------------------------------------------------------------------------*/
public class TestPara { public static void main(String[] args) { String str = "zhangmingming"; System.out.println ("The derive string object is :" + str); // Define a string object TestPara.changeParameter(str); System.out.println("The string object value is :" + str); } public static void changeParameter(String parameter ) { parameter = "billzhangmingming"; System.out.println ("The changed parameter is :" +parameter); } } /*----------------------------------------------------------------------------------------------*/
The derive string object is :zhangmingming The changed parameter is :billzhangmingming The string object value is :zhangmingming Press any key to continue... 在 changeParameter方法里,将传递进来的对象的reference改变了,这使得对象reference的拷贝引用指向了别的对象,所以它并没有对传入的对象值做任何改变。
<8> Super 关键字:指自身对象的父类。它可以: (1) 调用父类构造函数 (2)调用父类成员或方法 使用格式: super.member(member可以是函数或方法)
For example: /*----------------------------------------------------------------------------------------------*/ class SuperClass { String name = "zmm"; SuperClass() { System.out.println ("Call super class default construct!!!!!!!"); } SuperClass(int a) { System.out.println ("Call super class that has one of parameter construct!!!!!!!!!!"); }
} class ExtendsSuperClass extends SuperClass { String name = "Bill"; ExtendsSuperClass() { super(); //No problem System.out.println ("The child class construct "); // super(); // call to super must be first statement in constructor. } ExtendsSuperClass(int a) { super(a); } void chanageName(String superName,String subClassName) { super.name = "zhangmingming"; //Invoke super class atrribue and change it. this.name = "billzhangmingming"; } void showMyName() { System.out.println ("The superClass name is :" + super.name); System.out.println ("The subClass name is :" + this.name); } } public class TestSuper { public static void main(String[] args) { ExtendsSuperClass test; test = new ExtendsSuperClass(); int a = 10; test = new ExtendsSuperClass(a); test.showMyName(); } } /*----------------------------------------------------------------------------------------------*/ NOTICE: (1)如果Super关键字写在了ExtendsSuperClass 默认构造函数打印语句之后程序则会在编译时产生如下错误: F:\homeWork\JAVA\TestSuper.java:17: call to super must be first statement in constructor super(); ^ 1 error (2)子类以隐藏(覆写)了父类name属性,但使用Super便可轻松的访问父类的属性,并没有被子类的覆写所影响。 RESULT : Call super class default construct!!!!!!! The child class construct Call super class that has one of parameter construct!!!!!!!!!! The superClass name is :zmm The subClass name is :Bill Press any key to continue...
<9> Static 简介 : 静态成员不必依靠类的对象来访问,如果类中的成员被声明为Static,则该成员(属性或方法)就可以在类创建对象之前被访问,Static方 法的经典例子就是main方法,因为在程序开始执行时必须首先调用main(),所以它被声明为Static。 静态函数与变量可以使用类名称直接调用,这是由于static成员并不依靠任何类对象特征的体现。 如:ClassName.StaticMember (这个特性,不禁让我让我想起了“大史记”中的那句经典对白:“我不是你二叔,我是玉帝派来的神仙,只不过是借用你二叔的肉身而已!!!”) 也可以使用静态成员所在类的对象名来访问 如:Obj.StaticMember。 可以将声明为static的变量看作是全局变量,如果一个类中包含有static变量,则在声明一个对象时,并没有产生static变量的拷贝, 如果类中的方法需要使用自己类里被声明为static变量则有两种访问方式: 1)将方法声明为static。 2)使用本类的类名来调用。也就是上面提到的ClassName.StaticMember。 3)如果需要将static变量当参数传给一个方法,则该方法必须被声明为static(这是初学Java在编程时常犯的错误之一)。
EXAMPLE: /*----------------------------------------------------------------------------------------------*/ public class TestStatic { static int i = 10; public static void main(String args[]) { StaticClassMember a = new StaticClassMember(); a.method1(); // Call static member used object name. System.out.println ("The static property value is :" + TestStatic.i); i = i + 5; System.out.println ("The static property value is :" + TestStatic.i); aaa(i); // Passing static member.It's little funny.
} static void aaa( int a) {} }
class StaticClassMember { static void method1() { System.out.println ("The static method1"); } }
/*----------------------------------------------------------------------------------------------*/
The static method1 The static property value is : The static property value is :
NOTE : 无论你创建了多个TestStatic,它们都会使用同样的i变量,因为所有的对象都引用了同样的内存地址。

|