构造器用于对类实例进行初始化操作,构造器支持重载,如果多个重载的构造器里包含了相同的初始化代码,则可以把这些初始化代码放置在普通初始化块里完成 ,初始化块总在构造执行前被调用。
Java语言里定义类的简单语法如下:
[修饰符] class 类名
{
零个到多个构造器定义..
零个到多个属性...
零个到多个方法...
}
定义属性的语法格式如下:
[修饰符] 属性类型 属性名 [=默认值]
属性语法格式的详细说明如下:
*修饰符:修饰符可以省略,也可以是public,protected,private,static,final,其中public,protected,private三个最多只能出现其中之一,可以与static,final组合起来修饰属性。
*属性类型:属性类型可以是Java语言允许的任何数据类型,包括基本类型和现在介绍的引用类型。
*属性名:属性名则只要是一个合法的标识符即可,但这只是从语法角度来说的;如果从程序可读性角度来看,属性名应该由一个或多个有意义的单词连缀而成,第一个单词首字母小写,后面的每个单词首字母大写,其他字母全部小写,单词与单词之间不需要使用任何分隔符。
*默认值:定义属性还可以定义一个可选的默认值。
定义方法的语法格式如下:
[修饰符] 方法返回值类型 方法名(形参列表)
{
//由零条到多条可执行性语句组成的方法体
}
方法语法格式的详细说明如下:
* 修饰符:修饰符可以省略,也可以是public,protected,private,static,final,abstract,其中public,protected,private三个最多只能出现其中之一;abstract和final最多只能出现其中之一,它们可以与static组合起来修饰方法。
*方法返回值类型:返回值类型可以是Java语言允许的任何数据类型,包括基本类型和引用类型;如果声明了方法返回值类型,则方法体内必须有一个有效的return语句,该语句返回一个变量或一个表达式,这个变量或者表达式的类型必须与此处声明的类型匹配。除此之外,如果一个方法没有返回值,则必须使用void来声明没有返回值。
*方法名:方法名命名规则 与属性命名规则基本相同,但通常建议方法名以英文中的动词开头。
*形参列表:形参列表用于定义该方法接受的参数,形参列表由零组到多组“参数类型 形参名”组合而成,多组参数之间以英文(,) 隔开,形参类型和形参名之间以英文空格隔开。一旦在定义方法时指定了形参列表,则调用该方法时必须传入对应他的参数值---谁调用,谁负责形参赋值。
构造器的语法格式如下:
[修饰符] 构造器名 (形参列表)
{
//由零条到多条可执行性语句组成的构造器执行体
}
构造器语法格式的详细说明如下:
*修饰符:修饰符可以省略,也可以是public,protected,private其中之一。
*构造器名:构造器名必须和类名相同。
*形参列表:和定义方法形参列表的格式完全相同。
对象this的引用:
this关键字是一个对象的默认引用。this关建字总是指向调用该方法的对象。根据this出现的位置不同,this作为对象的默认引用有两种情形:
*构造器中引用该构造器执行初始化的对象。
*在方法中引用调用该方法的对象。
public calss ThislnConstructor
{
//定义一个名为foo的属性
public int foo;
public ThislnConstructor()
{
//在Test构造器里定义了一个foo对象
int foo=6;
//使用this代表此构造器进行初始化的对象
//下面的代码将会把刚创建对象的foo属性设置为6。
this.foo=6;
}
public static void main(String[] args){
//所有使用ThislnConstructor创建的对象的foo属性
//都将被设为6,所有下面代码将输出6.
System.out.println(new ThislnConstructor().foo);
}
}
dangthis作为对象的默认引用使用时,程序可以像访问普通引用变量一样来访问这个this引用,甚至可以把this当成普通方法的返回值。
public class ReturnThis
{
public int age;
public ReturnThis grow()
{
g++;
//return this;返回调用该方法的对象
return this;
}
public static void main(String[] args){
ReturnThis rt=new ReturnThis();
//可以连续调用同一个方法
rt.grow();
.grow();
System.out.println("rt的age属性值是:"+rt.age);
}
}
引用类型的参数传递:
public class TestRefereneTransfer
{
public static void swap(DataWrap dw)
{
//下面三行到吗实现dw的a,b属性值交换。
//定义一个临时变量来保存dw对象的a属性的值
int tem=dw.a;
//把dw对象的b属性值赋给a属性
dw.a=dw.b;
//把临时变量tmp的值赋给dw对象的b属性
dw.b=tmp;
System.out.println("swap方法里,a属性的值是"+dw.a+";bde值是"+dw.b);
}
public static void main(String[] args){
Datawrap dw=new DataWrap();
dw.a=6;
dw.b=9;
sqap(dw);
System.out.println("交换结束后,a属性的值是"+dw.a+";b属性的值是"+dw.b);
}
}
形参长度可变的方法:
public calss Varargs{
//定义了形参长度可变的方法
public static void test(int a,String...books){
//books被当成数组处理
for(String tem:books){
System.out.println(tmp);
}
//输出整数变量a的值
System.out.println(a);
}
public static void main(String[] args){
//调用test方法
test(5,"Struts2权威指南","基于J2EE的Ajax宝典");
}
}
成员变量和局部变量
成员变量指的是在类范围里定义的变量(属性)
局部变量指的是在同一个方法内定义的变量。
成员变量被分为类属性和实例属性两种,定义一个属性时不使用static修饰的就是实例属性,使用static修饰的就是类属性。其中类属性从这个类的准备阶段起开始存在,直到系统完全销毁这个类,类属性的作用域与这个类的生存范围相同;而实例属性则从这个类的实例被创建开始起存在,直到系统完全销毁这个实例了,实例属性的作用域与对应实例的生存范围相同。
成员变量的初始化和内存中的运行机制
//创建第一个Person对象
Person p1=new Person();
//创建第二个Person对象
Person p2=new Person();
//分别为两个Person对象的name属性赋值
p1.name="张三";
p2.name="孙悟空";
//分别为两个Person对象的eyeNum属性赋值
p1.eyeNum=2;
p2.eyeNum=3;
局部变量的初始化和内存中的运行机制
局部变量定义后,必须经过显示初始化才能使用,系统不会为局部变量执行初始化。这意味着定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始值时,系统才会局部变量分配内存,并将初始值保存到这块内存中。
与成员变量不同,局部变量不属于任何类或实例,因此它总是保村在该变量对应内存中;如果局部变量是一个引用类型的变量,则这个变量里存放的是地址,通过该地址引用到该变量实际引用i的对象或数组。
成员变量的作用域扩大到类存在范围或者对象存在范围,这种范围扩大的两大害处:
*增大了变量的生存时间,这将导致更大的系统开销。
*扩大了变量的作用域,这不利于提高程序的内聚性。
隐藏和封装
封装是面向对象三大特征之一(另外两个是继承和多态),他指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
一个类或对象实现良好的封装,可以实现一下目的:
*隐藏类的实现细节
*让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对属性的不合理访问。
*可进行数据检查,conger有利于保证对象信息的完整性
*便于修改,提高代码的可维护性
为了实现良好的封装,需要从两个方面考虑:
*将对象的属性和实现细节隐藏起来,不允许外部直接访问
*把方法暴露出来,让方法来操作或访问这些属性。
使用访问控制符
Java提供了三个访问控制符:private,protected和public,分别代表了三个访问控制级别,另外还有一个不加任何访问控制符的访问控制级别,提供了四个访问控制级别,访问控制级别由小到大依次:
private --- default --- protected --- public
访问控制级别由小到大
*private访问控制级别:如果类里的一个成员(包括属性和方法)使用private访问控制符来修饰,则这个成员只能在该类的内部被访问。很显然,这个访问控制符用于修饰属性最合适,使用他来修饰属性就可以把属性隐藏在类的内部。
*default访问控制权限(包访问权限):如果类里的一个成员(包括属性和方法)或者一个顶级类不使用任何访问控制修饰符,我们就称它为默认访问控制,default访问控制的成员或顶级类可以被相同包下其他类访问。
*protected访问控制权限(子类的访问权限):如果一个成员(包括属性和方法)使用protected访问控制符修饰,那么这个成员既可以被同一个包中其他类访问,也可以被不同包中的子类访问。通常情况下,如果使用protected来修饰一个方法,通常是希望其子类来重写这个方法。
*public访问控制权限(公共访问权限):这是一个最宽松的访问控制级别,如果一个成员(包括属性和方法)或者一个顶级类使用了public修饰,这个成员或顶级类就可以被所有类访问,不管是访问类和被访问类是否处于同一个中,是否具有父子继承关系。
关于访问控制符的作用,存在如下几条基本原则:
* 类里的绝大部分属性都应该使用private修饰,除了一些static修饰的,类似全局变量的属性,才可能考虑使用public修饰。除此之外,有些方法只是用于辅助实现该类的其他方法,这些方法成为被称为工具方法,工具方法也应该使用private修饰。
*如果某个类主要用做其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
*希望暴露出来给其他类自由调用的方法应该使用public修饰。因此,类的构造器通过使用public修饰,暴露给其他类中创建该类的对象,因为顶级类通常都希望被其他类自由使用,所以大部分顶级类都使用public修饰。
Java源文件的大体结构如下:
package语句 //0个或一个,必须放在文件开始
import | import static语句 //0个或多个,必须放在所有类定义之前
classDefinition | interfaceDefinition //0个或多个普通类或接口定义
Java的常用包
*java.lang:这个包下包含java语言的核心类,如String,Math,System和Thread类等,使用这个包下的类无须使用import语句导入,系统会自动daoru这个包下所有类。
*java.util:这个包下包含了java大量工具类/接口和集合框架类/接口,例如Arrays和list,Set等。
*java.net:这个包下包含了一些java网络编程相关的类/接口。
*java.io:这个包下包含了一些java输入/输出编程相关的类/接口。
*java.text:这个包下包含了一些java格式化相关的类。
*java.sql:这个包下包含了一些java进行JDBC数据库编程的相关类/接口
*java.awt:这个包下抽象窗口工具集(Abstract Window Toolkits)的相关类/接口,这些类主要用于构建图形用户界面(GUI)程序。
*java.swing:这个包下包含Swing图形用户界面程序编程的相关类/接口,这些类可以用于构建平台无关的GUIchengxu。
继承的特点
java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类被称为父类,有上网也被称为基类,超类。
因为子类是一种特殊的父类,因此父类包含的范围总比子类包含的范围要大,所以可以认为父类是大类,而子类是小类。
java里子类继承父类的语法格式如下:
修饰符 class SubClass extends SuperClass
{
//类定义部分
}
java使用extends作为继承的关键字,extend关键字在英文是扩展,而不是继承,这个关键字很好的体现了子类和父类的关系:子类是对父类的扩展,子类是一种特殊的父类。从这个意义上来说,使用继承来描述子类和父类关系是错误的,用扩展更恰当。
子类继承父类的特点
public class Fruit
{
public double weight;
public void info()
{
System.out.println("我是一个水果!重"+weight+"g!");
}
}
Fruit类的子类
public class Apple extends Fruit
{
public static void main(String[] args){
//创建Apple的对象
Apple a=new Apple();
//Apple对象本身没有weight属性
//因为Apple的父类有weight属性,也可以访问Apple对象的属性
a.weight=56;
//调用Apple对象的info方法
a.info();
}
}
重写父类的方法
鸵鸟需要重写鸟类的方法
public class Bird
{
//Bird类的fly方法
public void fly()
{
Sysotm.out.println("我在天空里自由自在的飞翔。。。");
}
}
重写Bird的fly方法
public class Ostrich extends Bird
{
//重写Bird类的fly方法
public void fly()
{
System.out.println("我只能在地上奔跑。。。");
}
public static void main(string[] args)
{
//创建Ostrich对象
Ostrich os=new Ostrich();
//执行Ostrich对象的fly方法,将输出“我只能在地上奔跑。。。”
os.fly();
}
子类中重新定义新方法
class BaseClass
{
//test方法是private访问权限,子类不可以访问该方法
private void test(){...}
}
class SubClass extends BaseClass
{
//此处并不是方法重写,所以可以增加static关键字
public static void test(){...}
}
}
父类实例的super引用
public void calloverridedMethod()
{
//在子类方法中通过super显式调用父类被覆盖的实例方法。
super.fly();
}
调用父类构造器
在一个构造器中调用另一个重载的构造器使用this调用来实现,在子类构造中调用父类构造器使用super调用来实现。
class Base
{
public double size;
public String name;
public Base(double size,String name)
{
this.size=size;
this.name=name;
}
}
public class Sub extends Base
{
public String color;
public Sub(double size,String name,String color)
{
//通过super调用来调用父类构造器的初始化过程
super(size ,name);
this.color=color;
}
public static void main(String[] args)
{
sub s=new sub(5.6,"测类对象","红色");
//输出sub对象的三个属性
System.out.println(s.size+"--"+s.name+"--"+s.color);
}
}
子类构造器调用父类构造器分如下几种情况:
*子类构造器执行体的第一行使用super显式调用父类构造器,系统将根据super调用里传入的实参列表调用父类对应的构造器。
*子类构造器执行体的第一行代码使用this显式调用本类中重载的构造器,系统将根据this调用里传入的实参列表调用本类另一个构造器。执行本类中另一个构造器时即会调用父类的构造器。
*子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参数的构造器。