2.1介绍类与对象
在现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即静态部分与动态部分。静态部分,顾名思义,就是不能动的部分,这个部分被称为“属性”,任何对象都具备其自身属性,如一个人,其属性包括高矮、胖瘦、性别、年龄等。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。
2.2 类
类就是同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的的规范,如一只鸟具有一对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟都具有翅膀这个特性和和飞行的技能,这样具有相同特性和行为的一类事物就称为类,类的思想就是这样产生的。类是封装对象的属性和行为载体,具有相同属性和行为的一类实体被称为类。
2.3面向对象程序设计具有以下特点:
封装性。继承性。多态性。
1.封装
封装是面向对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。例如,用户使用计算机时,只需要使用手指敲击键盘就可以实现一些功能,无须知道计算机内部是如何工作的,即使可能知道计算机的工作原理,但在使用计算机时也并不完全依赖于计算机工作原理这些细节。
采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易地直接操作此数据结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。
2.继承
继承性主要利用特定对象之间的共有属性。
3.多态
将父类对象应用于子类的特征就是多态,多态的实现并不依赖具体类,而且抽象类和接口。
2.4 类与对象
2.4.1 成员变量
在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样。
语法如下:
数据类型 变量名称[=值];
其中,[ = 值]表示可选内容,即定义变量时可以为其赋值,也可以不为其赋值。
2.4.2成员方法
1.成员方法的定义
定义成员方法的语法格式如下:
[权限修饰符]【返回值类型]方法名( [参数类型参数名 ] ) [throws异常类型]{
… //方法体
return 返回值;
}
其中,“权限修饰符”可以是private、public、protected中的任一个,也可以不写,主要用来控制方法的访问权限,关于权限修饰符将在下一章中详细讲解;“返回值类型”指定方法返回数据的类型,可以是任何类型,如果方法不需要返回值,则使用 void关键字;一个成员方法既可以有参数,
也可以没有参数,参数可以是对象也可以是基本数据类型的变量
代码如下:
public void showGoods() {
System.out.println("库存商品名称:");
System.out.println(FullName);
}
2.成员方法的参数
调用方法时可以给该方法传递一个或多个值,传给方法的值叫做实参,在方法内部,接收实参的变量叫做形参,形参的声明语法与变量的声明语法一样。形参只在方法内部有效。Java 中方法的参数主要有3种,分别为值参数、引用参数和不定长参数.
(1)值参数
值参数表明实参与形参之间按值传递,当使用值参数的方法被调用时,编译器为形参分配存储单元,然后将对应的实参的值复制到形参中,由于是值类型的传递方式,所以,在方法中对值类型的形参的修改并不会影响实参。
示例代码:
public class Can {
private int add(int x,int y){ //计算两个数的和
x=x+y;//对x进行加y操作
return x;//返回x
}
public static void main(String[] args) {//主方法
Can book=new Can();//创建Book对象
int x=30;//定义实参变量x
int y=40;//定义实参变量y
System.out.println("运行结果:"+book.add(x,y));//输出运行结果
System.out.println("实参x的值:"+x);//输出实参x的值
}
}
(2)引用参数
如果在给方法传递参数时,参数的类型是数组或者其他引用类型,那么,在方法中对参数的修改会反映到原有的数组或者甘他引用米刑上.这种类型的方法参数,我们称之为引用参数。
示例代码:
zpublic class RefTest {//类名
public static void main(String[] args) { //主方法
RefTest refTest=new RefTest(); //创建RefTest对象
int[]i={0,1,2}; //定义一维数组,作为方法的实参
System.out.print("原始数据:"); //输出内容
for(int j=0;j<i.length;j++){/ /遍历数组
System.out.print(i[j]+" "); //输出数组元素
}
refTest.change(i); //调用方法改变数组元素的值
System.out.print("\n修改后的数据:"); //输出信息
for(int j=0;j<i.length;j++){ //遍历数组
System.out.print(i[j]+" "); //输出数组元素
}
}
public void change(int[]i){//给数组赋值的方法
i[0]=100;/ /给数组与元素赋值
i[1]=200; //给数组与元素赋值
i[2]=300; //给数组与元素赋值
}
}
(3)不定长参数
声明方法时,如果有n个相同类型的参数,可以定义为不定长参数,该类型的参数声明如下:
权限修饰符 返回值类型 方法名(参数类型 参数名称)
示例代码:
public class Can {
public static void main(String[] args) { //主方法
Can multi=new Can(); //创建对象
System.out.print("运算结果:"+multi.add(20,30,40,50,60));//输出信息并调用计算总和方法
}
int add(int...x){ //定义add方法,并指定不定长参数的类型为int
int result=0; //定义一个整型变量
for(int i=0;i<x.length;i++){ //遍历数组
result+=x[i]; //将数组中元素的值相加
}
return result; //返回运算结果
}
}
2.5构造方法
在类中除了成员方法之外,还存在一种特殊类型的方法,那就是构造方法。构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自动调用构造方法。
构造方法的特点如下:
(1)构造方法没有返回类型,也不能定义为 void.(2)构造方法的名称要与本类的名称相同。
{3)构造方法的主要作用是完成对象的初始化工作,它能把定义对象的参数传给对象成员
在定义构造方法时,构造方法没有返回值,但这与普通没有返回值的方法不同,普通没有返回值的方法使 public void methodEx()这种形式进行定义,但构造方法并不需要使用 void关键字进行修饰。
构造方法的定义语法如下:
class Book {
public Book() { //构造方法
}
Public:构造方法修饰符。
Book:构造方法的名称。
在构造方法中可以为成员变量赋值,这样当实例化一个本类的对象时,相应的成员变量也将始化。如果类中没有明确定义构造方法,则编译器会自动创建一个不带参数的默认构造方法。
除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,即有参数构造方法
语法如下:
class Book{
public Book(int args) { //有参数构造方法
//对成员变量进行初始化
}
}
public:构造方法修饰符Book:构造方法的名称。
args:构造方法的参数,可以是多个参数。
注意:
如果在类中定义的构造方法都是有参构造方法,则编译器不会为类自动生成一个默认的无参构造方法,当试调用无参构造方法实例化一个对象时,编译器会报错。所以只有在类中没有定义任何构造方法时,编译器才在该类中自动创建一个不带参数的构造方法。
构造方法除了可以用public修饰以外,还可以用private修饰,即私有的构造方法,私有构造法无法使用new创建对象,这时需要使用静态方法生成类的对象。
示例代码:
public class Can {
private Can()
{ //私有构造方法
} //静态公开方法,向图书馆借书
static public Can libraryBorrow()
{ //创建静态方法,返回本类实例对象
System.out.println("通过调用静态方法创建对象"); //输出信息
return new Can(); //返回本类实例对象
}
public static void main(String[] args) { //主方法
Can book=Can.libraryBorrow(); //创建一个书的对象,不是new实例化的,而是通过方法从图书馆借来的
}
}
2.6对象的销毁
每个对象都有生命的周期,当对象的生命周期结束时,分配给该对象的内存地址会被回收。在其它语言中需要手动回收废弃的对象,但在Java拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收站将回收无用的但占用内存的资源。何种对象会被Java虚拟机视为垃圾。
(1)对象引用超出其作用范围,这个对象将被视为垃圾
(2)将对象赋值为null。
finalize()方法可进行垃圾回收但不一定会发生
System.gc()方法强制启动垃圾回收器。
2.7 this关键字
this引用的就是本类的一个对象,在局部变量或方法参数覆盖了成员变量时如果省略this关键字直接写成name=name,那只是把参数name赋值给参数变量本身而已员变量name的值没有改变,因为参数name在方法的作用域中覆盖了成员变量name,this 除了可以调用成员变量或成员方法之外,还可以作为方法的返回值。
代码如下:
public class Can { //创建Can类
String name="abc"; //定义一个成员变量
public void showName(String name)
{ //定义一个showName类并从传入一个参数
System.out.println(name); //输出
}
public static void main(String[] args) {
Can book=new Can(); //在Book2类定义一个对象
book.showName("123"); //调用showName方法
}
}
2.8static关键字
由static修饰的变量、常量和方法被称作静态变量、静态常量和静态方法,也被称为类的静态成员。静态成员是属于类所有的,区别于个别对象。
2.9 静态变量,常量,方法
语法如下:
static a ; // 静态变量
final static A; //静态常量
static public void b(){ //静态方法
}
3.0类的封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来。其载体就是类。
无封装代码如下:
public class Restaurant1 {//创建一个类
public static void main(String[] args) {//主方法
String cookName="Tom Cruise";//厨师的名字叫Tom Cruise
System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
System.out.println(cookName+"切葱花");//输出
System.out.println(cookName+"洗蔬菜");//输出
System.out.println(cookName+"开始烹饪"+"香辣肉丝");//输出
System.out.println("**请问厨师叫什么名字?***");//输出
System.out.println(cookName);//输出
System.out.println("请让厨师给我切一点葱花。***");//输出
System.out.println(cookName+"切葱花");//输出
}
}
封装成类代码如下:
public class Restaurant2 {//创建一个类
public static void main(String[] args) {//主方法
Cook1 cook=new Cook1();//创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
cook.cooking("香辣肉丝");//厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");//输出
System.out.println(cook.name);//厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");//输出
cook.cutOnion();//厨师去切葱花
}
}
class Cook1{//创建类
String name;//厨师的名字
public Cook1(){//定义一个方法
this.name="Tom Cruise";//厨师的名字叫Tom Cruise
}
void cutOnion(){//厨师切葱花
System.out.println(name+"切葱花");//输出信息
}
void washVegetables(){//厨师洗蔬菜
System.out.println(name+"洗蔬菜");//输出信息
}
void cooking(String dish){//厨师烹饪顾客点的菜
washVegetables();//调用洗蔬菜方法
cutOnion();//调用切葱花方法
System.out.println(name+"开始烹饪"+dish);//输出信息
}
}
使用private修饰代码如下:
public class Restaurant4 {//创建类
private Cook2 cook=new Cook2();//餐厅封装的厨师类
public void takeOlder(String dish){//下单 Restaurant2 a=new Restaurant2();//创建一个对象
cook.cooking(dish);//通知厨师做菜
System.out.println("您的菜好了,请慢用。");//输出信息
}
public String saySorry(){//拒绝顾客请求
return"抱歉,餐厅不提供此项服务。";//返回字符串
}
public static void main(String[] args) {//主方法
Restaurant4 water=new Restaurant4();//创建餐厅对象,为顾客提供服务
System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
water.takeOlder("香辣肉丝");//服务员给顾客下单
System.out.println("**你们的厨师叫什么名字?***");//输出信息
System.out.println(water.saySorry());//服务员给顾客善意的答复
System.out.println("**请让厨师给我切一点葱花。***");//输出信息
System.out.println(water.saySorry());//服务员给顾客善意的答复
}
}
3.1类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性,在程序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性。其基本思想是基于某个父类的扩展,制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类中的某些方法。例如,平行四边形是特殊的四边形,可以说平行四边形类继承了四边形类,这时平行四边形类将所有四边形具有的属性和方法都保留下来,并基于四边形类扩展了一些新的平行四边形类特有的属性和方法。
3.2extends 关键字
让一个类继承另一个类,用extends关键字,语法如下:
child extends parents
child: 子类
parents:父类
extends:继承关键字
class Computer{//父类
String screen="液晶显示屏";
void startup(){//开机方法
System.out.println("电脑正在开机,请等待...");//输出
}
}
public class Pad extends Computer{//创建一个类并继承父类
String battery="5000毫安电池";//子类独有的属性
public static void main(String[] args) {//主方法
Computer pc=new Computer();//电脑类
System.out.println("computer的屏幕是:"+pc.screen);//输出
pc.startup();//调用父类方法
Pad ipad=new Pad();//平板电脑类
System.out.println("pad的屏幕是:"+ipad.screen);//子类可以直接使用父类属性
System.out.println("pad的屏幕是:"+ipad.battery);//子类独有的属性
ipad.startup();//子类可以直接使用父类方法
}
}
3.2方法的重写
1.重写的实现
继承并不只是扩展父类的功能,还可以重写父类的成员方法。重写(还可以称为覆盖)就是类中将父类的成员方法的名称保留,重新编写成员方法的实现内容,更改成员方法的存储权限,可修改成员方法的返回值类型。
示例代码:
class Computer2{//父类:电脑
void showPicture(){//定义一个方法
System.out.println("鼠标单击");//输出信息
}
}
public class Pad2 extends Computer2 {//创建一个类并继承父类
void showPicture(){//重写父类的方法
System.out.println("手指点击触摸屏");//输出信息
}
public static void main(String[] args) {//主方法
Computer2 pc=new Computer2();//电脑类
System.out.print("pc打开图片:");//输出信息
pc.showPicture();//调用方法
Pad2 ipad=new Pad2();//平板电脑类
System.out.print("ipad打开图片:");//输出信息
ipad.showPicture();//重写父类方法
Computer2 computerpad=new Pad2();//父类声明,子类实现
System.out.print("computerpad打开图片:");//输出信息
computerpad.showPicture();//调用父类方法,实现子类重写的逻辑
}
}
3.3所有类的父类--Object类
使用 class关键字定义类时,就应用了继承原理,因或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是 Java 类层中的最高层类。当创建一个类 class时,总是在继承,除非某个类已经指定要从其他类继承,否则它就是从java.lang.Object类继承而来的,可见Java中的每个类都源于java.lang.Object类,如String、Integer等类都是继承于Object类;除此之外自定义的类也都继承于Object类。由于所有class类都是Object子类,所以在定义类时,省略了 extends Object关键字,在Object类中主要包括cloneO、finalizeequals、toString0等方法,其中常用的两个方法为equals()和toString0方法。由于所有的类都是Object类的子类,所以任何类都可以重写 Object类中的方法。
1.getClass()方法
getClass()方法是Object类定义的方法,它会返回对象执行时的 Class实例,然后使用此例用getName()方法可以取得类的名称。
语法如下:
getclass().getName();
可以将getClass()方法与toString()方法联合使用。
2. toString()方法
toString0方法的功能是将一个对象返回为字符串形式,它会返回一个 String实例。在实际的营用中通常重写toString0)方法,为对象提供一个特定的输出模式。当这个类转换为字符串或与字符甲连接时,将自动调用重写的 toString()方法。
示例代码:
public class Can {//创建类
public String toString(){//重写toString()方法
return "在"+getClass().getName()+"类中重写toString()方法";//返回值
}
public static void main(String[] args) {//主方法
System.out.println(new Can());//调用方法并输出,打印本类对象
}
}
3.equals()方法
equals()方法,是比较“==”运算符与equals()方法,说明”==”比是两个对象的引用是否相等,而equals0方法比较的是两个对象的实际内容。
示例代码:
public class Can {//创建类
public static void main(String[] args) {//主方法
String s1="123";//实例化两个对象,内容相同
String s2="123";//实例化对象
System.out.println(s1.equals(s2));//使用equals()方法
Can v1= new Can();//实例化两个类对象
Can v2=new Can();//实例化对象
System.out.println(v1.equals(v2));//使用equals()方法
}
}
3.4类的多态
多态意为一个名字可具有多种语义,在程序设计语言中,多态性是指“一种定义,多种实现”例如,运算符“+”作用于两个整型量时是求和,而作用于两个字符型量时则是将其连接在一起。用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。类的多态性可以从两方面体现:一是方法的重载,二是类的上下转型
3.4.1 方法的重载
我们知道构造方法的名称由类名决定,所以构造方法只有一个名称,但如果希望以不同的方式来实例化对象,就需要使用多个构造方法来完成。由于这些构造方法都需要根据类名进行命名,为了让方法名相同而形参不同的构造方法同时存在,必须用到“方法重载”虽然方法重载起源于构造方法,但是它也可以应用到其他方法中。
方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同就可。
示例代码:
public class Can {//创建类
public static int add(int a){//定义一个方法并传入一个int型参数
return a;//返回一个整型值
}
public static int add(int a,int b){//定义一个方法并传入两个参数
return a+b;//返回a+b的值
}
public static double add(double a,double b){//定义一个方法并传入两个参数
return a+b;//返回a+b的值
}
public static int add(int a,double b){//定义一个方法并传入两个参数
return (int)(a+b);//返回a+b的值,同时利用强制转换成int型
}
public static int add(double a,int b){//定义一个方法并传入两个参数
return (int)(a+b);//返回a+b的值,同时利用强制转换成int型
}
public static int add(int...a){//定义一个不定长参数方法
int s=0;//定义一个int型变量并赋予初值
for(int i=0;i<a.length;i++){//遍历数组
s+=a[i];//总计
}
return s;//返回s的值
}
public static void main(String[] args) {//主方法
System.out.println("调用add(int)方法:"+add(1));//调用方法并输出
System.out.println("调用add(int,int)方法:"+add(1,2));//调用方法并输出
System.out.println("调用add(double,double)方法:"+add(2.1,3.3));//调用方法并输出
System.out.println("调用add(int a,double b)方法:"+add(1,3.3));//调用方法并输出
System.out.println("调用add(double a,int b)方法:"+add(2.1,3));//调用方法并输出
System.out.println("调用add(int...a)不定长参数方法:"+add(1,2,3,4,5,6,7,8,9));//调用方法并输出
System.out.println("调用add(int...a)不定长参数方法:"+add(2,3,4 ));//调用方法并输出
}
}
3.4.2 向上转型
子类转变成父类类型
示例代码:
class Quadrangle{//四边形类
public static void draw(Quadrangle q){//四边形类中的方法
//SomeSentence
}
}
public class Parallelogram extends Quadrangle{//平行四边形类,继承了四边形类
public static void main(String args[]){//主方法
Parallelogram p=new Parallelogram();//实例化平行四边形类对象引用
draw(p);//调用父类方法
}
}
3.4.3 向下转型
父类转变成子类 使用强制转换
代码如下:
class Quadrangle{//父类
public static void draw(Quadrangle q){//父类方法
//SomeSentence
}
}
public class Parallelogram extends Quadrangle {//子类继承父类
public static void main(String[] args) {//主方法
draw(new Parallelogram());//调用方法并传入子类对象
Quadrangle q=new Parallelogram();//将平行四边形对象看作是四边形对象,称为向上转型操作
Parallelogram p=q;//向下转型
}
}
3.5 instanceof关键字
当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生CastException 异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否子类对象的实例。这个判断通常使用instanceof操作符来完成。可以使用instanceof操作符判断是一个类实现了某个接口(接口会在74节中进行介绍),也可以用它来判断一个实例对象是否属于个类。
instanceof的语法格式如下:
myobject instanceof ExampleClass
myobject:某类的对象引用。ExampleClass:某个类。
使用instanceof操作符的表达式返回值为布尔值。如果返回值为true,说明myobject 对象ExampleClass 的实例对象;如果返回的值为false,说明myobject对象不是ExampleClass的实例对象。
代码如下:
class Quadrangle{//类名
public static void draw(Quadrangle q){//构造一个方法并传入一个参数
//SomeSentence
}
}
class Square extends Quadrangle{//构造一个类并继承另一个类
//SomeSentence
}
class Anything{//构造一个类
//SomeSentence
}
public class Parallelogram extends Quadrangle {//创建一个类并继承另一个类
public static void main(String[] args) {//主方法
Quadrangle q=new Quadrangle();//创建一个对象
if(q instanceof Parallelogram){//判断该对象是否属于该类
Parallelogram p=(Parallelogram)q;//进行强制转换
}
if(q instanceof Square){//判断该对象是否属于该类
Square s=(Square) q;//进行强制转换
}
System.out.println(q instanceof Anything );//输出信息
}
}
3.6 抽象类与接口
3.6.1抽象类与抽象方法
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。回提继承和多态原理,继承树中越是在上方的类越抽象,如鸽子类继承鸟类、鸟类继承动物类等。在多态机制中,并不需要将父类初始化对象,我们需要的只是子类对象,所以在 Java 语言中设置抽象不可以实例化对象,因为图形类不能抽象出任何一种具体图形,但它的子类却可以。
Java中定义抽象类时,需要使用abstract关键字,其语法如下:
[权限修饰符] abstract class 类名 {
类体
}
使用abstract关键字定义的类称为抽象类,而使用abstract关键字定义的方法称为抽象方法,抽象方法的定义语法如下:
[权限修饰符] abstract 方法返回值类型 方法名 (参数列表);
示例代码:
public abstract class Market {//创建类
public String name;//商场名称
public String goods;//商品名称
public abstract void shop();//抽象方法,用来输出信息
}
public class TaobaoMarket extends Market {//创建类并继承商场类
@Override
public void shop() {//重写方法
// TODO Auto-generated method stub
System.out.println(name+"网购"+goods); //输出信息
}
}
public class GoShopping {//类名
public static void main(String[] args) {//主方法
// TODO Auto-generated method stub
Market market=new WallMarket();//向上转型
market.name="沃尔玛";//赋值
market.goods="七匹狼西服";//赋值
market.shop();//调用方法
market=new TaobaoMarket();//创建一个对象
market.name="淘宝";//赋值
market.goods="韩都衣舍花裙";//赋值
market.shop();//调用方法
}
}
综上所述,使用抽象类和抽象方法时,需要遵循以 下原则:
(1)在抽象类中,可以包含抽象方法,也可以不包已含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。
(2)抽象类不能直接实例化,即使抽象类中没有声 明抽象方法,也不能实例化。
(3)抽象类被继承后,子类需要实现其中所有的抽象方法。
(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。使用抽象类时,可能会出现这样的问题:程序中会有太多冗余的代码,同时这样的父类局限生很大,例如,上面的例子中,也许某个不需要 shop()方法的子类也必须重写shopO方法。如果将这个shopO方法从父类中拿出,放在别的类里,又会出现新问题,就是某些类想要实现“买衣服”的场景,竟然需要继承两个父类。Java 中规定,类不能同时继承多个父类,面临这种问题时,接口的概念便出现了。
3.7接口的声明及实现
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。
接口使用interface 关键字进行定义,语法如下:
[ 修饰符 ] interface 接口名 [ extends 父接口名列表 ] {
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为 public。如果省略则使用默认的访权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的 Java标识符。一般情况下要求首字母大写。extends父接口名列表:可选参数,用于指定要定义的接口继承
于哪个父接口。当使用extends关键字时,父接口名为必选参数。方法:接口方法定义而没有被实现。
一个类实现一个接口可以使用implements关键字,代码如下:
public class Parallelogram extends Quadrangle implements drawTest{
…//
}
3.8区分抽象类与接口
抽象类和接口都包含可以由子类继承实现的成员,但抽象类是对根源的抽象,而接口是对动作的抽象。抽象类的功能要远超过接口,那为什么还要使用接口呢?这主要是由于定义抽象类的代价高(因为每个类只能继承一个类,在这个类中,必须继承或编写出其子类的所有共性,因此,虽然接口在功能上会弱化许多,但它只是针对一个动作的描述,而且可以在一个类中同时实现多个接口,这样会降低设计阶段的难度。
抽象类和接口的区别主要有以下几点。
注意:
(1)子类只能继承一个抽象类,但可以实现任意多个接口。
声明类时,如果不使用p
(2)一个类要实现一个接口必须实现接口中的所有方法,而抽象类不必。
(3)抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public static finalf
口多学两招:
Java语言中,类的权限
(4)接口中只能定义抽象方法,而抽象类中可以定义非抽象方法。
定义一个public的doSt
(5)抽象类中可以有静态方法和静态代码块等,接口中不可以。
下面两段代码是等效的
(6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法。
3.9访问控制
3.9.1 访问控制符
前面介绍了面向对象的几个基本特性,其中包括封装性,封装实际上有两方面的含义:把谈藏的隐藏起来、把该暴露的暴露出来,这两个方面都需要通过使用Java提供的“访问控制符”来现,Java中的访问控制符主要包括public、protected、private和default(缺省)等4种,这些控育符控制着类和类的成员变量以及成员方法的访问权限。
使用访问控制符时,需要遵循以下原则。
(1)大部分顶级类都使用public修饰;
(2)如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写。而不想被外界直接调用,则应该使用protected修饰;
(3)类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性,才考虑使用public 修饰;
(4)当定义的方法只是用于辅助实现该类的其他方法(即工具方法),应该使用private修饰;(5)希望允许其他类自由调用的方法应该使用public修饰。
3.9.2 Java 类包
在Java中每定义好一个类,通过Java编译器进行编译之后,都会生成一个扩展名为class的文件,当这个程序的规模逐渐庞大时,就很容易发生类名称冲突的现象。那么JDK API中提供了成千上万具有各种功能的类,Java中提供了一种管理类文件的机制,就是类包。Java中每个接口或类都来自不同的类包,无论是JavaAPI中的类与接口还是自定义的类与接口都需要隶属于某一个类包,这个类包包含了一些类和接口。如果没有包的存在,管理程序中的类名称将是一件非常麻烦的事情,如果程序只由一个类定义组成,并不会给程序带来什么影响,但是险着程序代码的增多,难免会出现类同名的问题。例如,在程序中定义一个Login类,因业务需要,还要定义一个名称为Login 的类,但是这两个类所实现的功能完全不同,于是问题就产生了,编译器不会允许存在同名的类文件。解决这类问题的办法是将这两个类放置在不同的类包中,实际上 ava中类的完整名称是包名与类名的组合。
在类中定义包名的语法如下:
package包名1[.包名2[.包名3...]];
在上面的语法中。包名可以设置多个,包名和包名之间使用.分割,包名的个数没有限制,其中前面的包名包含后面的包名。
在类中指定包名时需要将package放置在程序的第一行,它必须是文件中的第一行非注释代码当使用package关键字为类指定包名之后,包名会成为类名中的一部分,预示着这个类必须指定全名。
4.0 成员内部类
在一个类使用内部类,可以在内部类中直接存取其所在类的私有成员变量。
语法如下:
public class OuterClass{ //外部类
private class InnerClass { //内部类
//...
}
}
在内部类中可以随意使用外部类的成员方法以及成员变量,尽管这些成员被修饰为private .
内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象。那么内部类对象就会绑定在外部类对象上。内部类初始化方式与其他初始化方式相同,都是使用new 关键字。
示例代码:
public class OuterClass {//创建类
innerClass in=new innerClass();//创建对象
public void ouf(){//方法
}
class innerClass{//类名
innerClass(){//方法
}
public void inf(){//方法
}
int y=0;//定义变量
}
public innerClass doit(){//方法
//y=4;
in.y=4;//调用变量
return new innerClass();//返回对象
}
public static void main(String[] args) {//主方法
OuterClass out=new OuterClass();//创建对象
OuterClass.innerClass in=out.doit();//调用方法
OuterClass.innerClass in2=out.new innerClass();//向上转型
}
}
4.1静态内部类
在内部类前添加修饰符static,这个内部类就变为静态内部类了,一个静态内部类可以声明静态成员,但是在非静态内部类中不可以声明静态成员。静态内部类有一个最大的特点,就是不能用外部类的非静态成员,所以静态内部类在程序开发中比较少见。
可以这样认为,普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象但如果内部类被定义为static,就会有更多的限制。
静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
示例代码:
public class StaticInnerClass {//创建类
int x=100;//定义一个整型变量并初始化
static class Inner{//内部类
void doitInner(){//方法
//System. out. printin("外部类"+x);//输出
}
public static void main(String args[]){//主方法
System. out. println();//换行
}
}
}