(原创) 脚踏实地学Java之:基础篇
最近与几个朋友闲聊技术,当谈起他们各自用JAVA做项目时所用到的技术时,夸夸其谈,不知所云,犹如布什总统竞选前的演讲一般精彩,听的我是云里雾里,一头雾水!但当我问他们一些基础JAVA语言机制,与面向对象的一些基本思想时,回答起来却吞吞吐吐与刚才“演讲”时的表情却荡然不在!我就纳闷了“谈话前后时间不超过十分钟,这差距咋就这么大呢!!哈哈!!!”。
好了,不闲扯了,谈正题吧。上边说了这么多,意思就是,学习就要跟做人做事一样,脚踏实地,一步一个脚印,在学习技术的路上容不得半点虚假,也没有所谓的捷径可走,如果你走了弯路,相信你总有一天还是再要走会来的。这就是我写这篇文章的目的,帮助那些正在学习或用JAVA做开发的人员掌握技术细节,打好基础。
注:本系列前几篇文章使用实例来讲解一些基础概念,以后的章节里会不断对JAVA机制深入。如果您是工作了几年的高手就帮我挑挑错,不胜感激!!!如果您是初学JAVA者,我建议你把我做的实例用你的理解重现一便,如果有技术问题可以共同探讨。我的邮箱地址:billzhangmingmging@sina.com.cn
(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变量,因为所有的对象都引用了同样的内存地址。