7.1 类的封装
封装:封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类.
例7.4 将厨师对象封装在餐馆类中,顾客无法接触到厨师任何信息.
这个例子我们就能够看出,作为顾客,我始终是和服务员进行 交流,再由服务员与厨师进行交流,整个过程中,顾客与厨师是完全没有任何交流的,作为顾客,我不知道我品尝的菜是哪位厨师烹饪出来的,这种编程模式就是封装.
将对象的属性和i行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想.
7.2 类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的d性,在程序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性.
7.2.1 extends 关键词
在Java中,让一个类继承另一个类,用extends关键字,语法如下:
child extend parents
注意:该继承只支持单继承,及,即一个子类只能继承一个父类.
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();//子类可以直接使用父类方法
}
}
7.2.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 cmputerpad = new Pad2();//父类声明,子类实现
System.out.print("computerpad打开图片:");
coputerpad.showPicture();//调用父类方法,实现子类重写的逻辑
}
}
2.super关键字
super关键字的使用方法与this关键字类似.this关键字代表本类对象,suoer关键字调用父类对象,使用方法如下:
super.propery;//调用父类的属性
super.method();//调用父类的方法
class Computer83{//父类:电脑
String sayHello(){
return "欢迎使用";
}
}
public class Pad3 extends Computer3{//子类:平板电脑
String sayHello() { //子类重写父类方法
return super.sayHello() +"平板电脑";//调用父类方法,在其结果后添加字符串
}
public static void main(String[] args){
Computer3 pc = new Computer3();//电脑类
System.out.println(pc.sayHello());
Pad3 ipad = new Pad3();//平板电脑类
System.out.println(ipad.sayHello());
}
}
7.2.3 所有类的父类---Object类
在Java中,所有的类都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是JAVA类层中的最高类.
Object类中的getClass(),notify(),notifyAll(),wait()等方法不能被重写,因为这些方法被定义为final类型.
Object类中几个重要方法.
1.getClass()方法
getClass()方法是Obiect类定义的方法,它会返回对象执行的Class实例,然后使用此实例调用getName()方法可以取得类的名称.
语法如下:getClass().getName();
可以将getClass()方法与toString()方法联合使用.
2.toString()方法
toString()方法的功能是将一个对象返回字符串形式,它会返回一个String实例.当这个类转换为字符串或字符串连接,将自动调用重写的toString()方法.
public class ObjectInstance {
public String toString() { //重写toString()方法
return "在" + getClass().getName() + "类中重写toString()方法";
}
public static void main(String[] args) {
System.out.println(new ObjectInstance()); //打印本类对象
}
}
3.equals()方法
前面章节曾讲解过equals()方法,当时是比较"=="运算符与equal()方法,说明"=="比较的是两个对象的引用是否相等,而equals()方法比较的是两个对象的实际内容.
class V {
}
public class OverWriteEquals {
public static void main(String[] agrs) {
String s1 = "123"; //实例化两个对象,内容相等
String s2 = "123";
System.out.println(s1.equal(s2)); //使用\equals()方法调用
V v1 = new V(); //实例化两个V类对象
V v2 = new V();
System.out.println(v1.equals(v2)); //使用equals()方法比较v1与v2对象
}
}
7.3 类的多态
多态意为一个名字具有多种语义,在程序设计语言中,多态性是指"一种定义,多种实现",例如,运算符"+"作用于两个整型量时是求和,而作用于两个字符型常量实则是将其连接在一起.利用多条可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理.类的多态性可以从两方面体现:一是方法的重载,二是类的上下转型.
7.3.1 方法的重载
方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可.
public class OverLoadTest { //定义一个方法
public static int add(int a) {
return a;
} //定义与第一个方法参数个数不同的方法
public static int add(int a ,int b) {
return a+b;
} //定义与第一个方法相同名称,参数类型不同的方法
public static double add(double a ,double b) {
return a+b;
} // 定义一个成员方法
public static int add(int a ,double b) {
return (int) (a+b);
}
//定义不定长参数
public static int add(int ... a ) {
int s = 0;//根据参数个数循环 *** 作
for (int i = 0;i
重载和重写都体现了面向对象的多态性,但重载与重写是两个完全不同的概念,重载主要用于一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同,而重写主要用于子类继承父类时,重新实现父类中的非私有方法.
7.3.2 向上转型
常规的继承图都是将顶级类设置在页面的顶部,然后逐渐向下,所以将子类对象看作是父类对象被称为"向上转型".
class Quadrangle { //四边形类
public static void draw (Quadrangle q) { //四边形类中的方法
//SomeStence
}
}
public class Parallelogram extends Quadrangle { //平行四边形类,继承了四边形类
public static void miain(String args[]) {
Parallelogram p = new parallelogram(); //实例化平行四边形类对象引用
draw(p); // 调用父类
}
}
7.3.3 向下转型
从下面代码可看出,越是具体的对象具有的有特性越多,越抽象的对象具有的特性越少.在做向下转型
*** 作时,将特性范围小的对象转换为特性范围大的对象肯定会出现问题,所以这时需要告知编译器这个四边形就是平行四边形.将父类对象强制转换为某一个子类对象 这种方式称为显示类型转换.
class Quadrangle { //四边形类
public static void draw (Quadrangle q) { //四边形类中的方法
//SomeStence
}
}
public class Parallelogram extends Quadrangle { //平行四边形类,继承了四边形类
public static void miain(String args[]) {
draw(new Parallelogram());
//将平行四边形类对象看作是四边形对象,称为向上转型 *** 作
Parallelogram p = new parallelogram();
//将父类对象赋予子类对象,并强制转换为子类型
Parallelogram p = (Parallelogram) q;
}
}
7.3.4 instanceof关键词
当在程序中执行向下转型 *** 作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例.这个通常用instanceof *** 作符来完成.可以使用instanceof *** 作符判断是否一个类实现了某个接口,也可以用来判断一个实例对象是否属于一个类.
instanceof语法如下:
myobiect 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
public class Parallelogram extends Quadrangle { //平行四边形类,继承了四边形类
public static void miain(String args[]) {
Quadrangle q = new Quadrangle(); //实例化父类对象
//判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Parallelogram) q; //进行向下转型 *** 作
}
//判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Square) {
Square s = (Square) q; //进行向下转型 *** 作
}
//由于q对象不为Anything类的对象,所以这条语句是错误的
//system.out.println(q instanceof Anything);
}
}
7.4 抽象类与接口
7.4.1 抽象类与抽象方法
在解决实际问题时,一般将父类被定义为抽象类,需要使用这个父类进行继承与多态处理.回想继承和多态原理,继承树中越是在上方的类越抽象,如鸽子类继承鸟类,鸟类继承动物类等.在多态机制中,并不需要父类初始化对象,我们需要的只是子类对象,所以在JAVA语言中设置抽象类不可以实例化对象,因为图形类不能抽象出任何一种具体图形,但他的子类却可以.
Java中定义抽象类时,需要使用abstract关键字,其语法如下:
abstract class 类名 {
类体
}
使用abstract关键字定义的类称为抽象类,而使用abstract关键字定义的方法称为抽象方法,抽象方法的定义语法如下:
abstract 方法返回值类型 方法名(参数列表);
从上面的语法可以看出,抽象方法是直接以分号结尾的,它没有方法体,抽象方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上,抽象类除了被继承之外没有任何意义.
构造方法不能定义为抽象方法
public abstract class Market {
public String name; //商场名称
public String goods; //商场名称
public abstract void shop(); //抽象方法,用来输出信息
定义一个TaobaoMarket类,继承自Market抽象类,实现其中的shop抽象方法;
public class TaobaoMarket extends Market {
@Override
public void shop() {
//TODO Auto-generated method stub
System.out.println(name+"网购"+goods);
}
}
定义一个WallMarket类,继承自Market抽象类,实现其中shop抽象方法:
public class WallMarket extends Market {
@Override
public void shop() {
//TODO Auto-generated method stub
System.out.println(name+"实体店购买"+goods);
}
}
public class GOShopping
{
public stadtic void main(String[] args)
{
Market market = new WallMarket();//使用费派生类对象创建抽象对象
Market.name = "沃尔玛";
market.goods = "七匹狼西服";
market.shop =();
market = new TaobaoMarket();//使用费派生类对象创建抽象对象
market.name = "淘宝";
market.goods = "韩都衣舍花裙";
market.shop();
}
}
使用抽象类和抽象方法时需要遵守以下原则:
(1)在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。
(2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法,也不能实例化。
(3)抽象类被继承后,子类需要实现其中所有的抽象方法。
(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
7.4.2 接口的声明及实现
接口是抽象的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体,可以将draw()方法封装到一个接口中,这样可以让一个类既能继承图形类又能实现draw()方法接口,这就是接口存在的必要性.
使用interface关键词进行定义,其语法如下:
[修饰符] interface 接口名 [extends 父接口名列表] {
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为public.
接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符.一般情况下要求首字母大写.
extends:父接口名列表:可选参数,用于指定要定义的接口继承于哪一个父接口,父接口名必为必选参数.
方法:接口中的方法只有定义而没有被实现.
一个类实现一个接口可以使用implements关键字
public class Parallelogram extends Quadrangle implements drawTest {
...//
}
7.4.3 多重继承
在Java中类不允许多重继承,但使用接口就可以实现多重继承,因为是一个类可以同时实现多个接口,这样可以将所有需要实现的接口放置在implements关键词后使用逗号","隔开,但可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法.
通过接口实现多重继承的语法如下:
class 类名 implements 接口1,接口2,...,接口n
如果是接口承接接口,使用extends关键字,而不是implements关键字,例如:
interface intf1 {
}
interface intf2 extends intf1 {
}
另外,如果遇到接口继承接口,则子类在实现子接口时,需要同时实现父接口和子接口中定义的所有方法,例如:
interface Father { //定义父接口
void fatherMethod();//父接口方法
}
interface Child extends Father { //定义子接口,继承父接口
void childMethod(); //子接口方法
}
public class InterfaceExtends implements Child { //实现子接口,但必须重新写所有方法
public void fatherMethod() {
System.out.println("实现父接口方法");
}
Public void childMethod() {
System.out.println("实现子接口方法");
}
}
7.4.4 区分抽象类与接口
抽象类和接口的区别主要有以下几点:
(1)子类·只能继承一个抽象类,但可以实现任意多个接口。
(2)一个类要实现去一个接口必须实现接口中的所有方法,而抽象类不必。
(3)抽象类中的成员变量是可以各种类型,而接口中的成员变量只能是public static final的。
(4)接口中只能定义抽象方法,而抽象类中可以定义非抽象方法。
(5)抽象类中可以有静态方法和静态代码块等,接口中不可以。
(6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法。
7.5 访问控制
7.5.1 访问控制符
所有访问控制符时,需要遵循以下原则。
(1)大部分顶级类都使用public修饰。
(2)如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰。
(3)类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性,才会考虑使用public修饰;
(4)当定义的方法只是用于辅助实现该类的其他方法,应该使用private修饰;
(5)希望允许其他类自由调用的方法应该使用public修饰。
7.5.2 Java类包
在Java中采用类包机制非常重要,类包不仅可以解决类名冲突问题,还可以在开发庞大的应用程序时,帮助开发人员管理庞大的应用程序组件,方便软件复用。
在类中定义包名的语法如下:
package 包名1 [.包名2[.包名3...] ];
注意:Java包的命名规则是全部使用小写字母,另外,由于包名将转换为文件的名称,所以包名不包括特殊字符
使用包中的类,其语法如下:
import 包名1 [.包名2[.包名3...] ].类名;
import com.lzw.*; //指定 com.lzw包中的所有类在程序中都可以使用
import com.lzw.Math ///指定 com.lzw包中的Math类在程序中可以使用
7.5.3 final关键字
1.final类
定义为final的类不能被继承
final的语法如下:
final class 类名{ }
final class FinalClass {
int a = 3;
void doit() {
}
Public static void main(String args[] ) {
FinalClass f = new FinalClass();
f.a++;
System.out.println(f.a);
}
}
2.final方法
private final void test() {
...//省略一些程序代码
}
class Parents {
private final void doit() {
System.out.println("父类。doit()");
}
final void doit2() {
System.out.println("父类。doit2()");
}
public void doit3() {
System.out.println("父类。doit3()");
}
}
class Sub extends Parents {
public final void doit() { //在子类中定义一个doit()方法
System.out.println("子类。doit()");
}
//final void doit2(){ //final方法不能覆盖
//System.out.println("子类.doit2()");
//}
public void doit3() {
System.out.println("子类.doit3()");
}
}
public class FinalClass {
public static void main(String[] args) {
Sub s = new Sub(); //实例化
s.doit(); //调用doit()方法
Parents p = s; //执行向上转型 *** 作
//p.doit(); //不能调用private方法
p.doit2();
p.doit3();
}
}
3、final 变量
final 关键字可用于变量声明(定义的变量必须在声明时对其进行赋值 *** 作) ,一旦该变量被设定,就不可以再改变该变量的值。
final double PI=3.14;
7.6 内部类
7.6.1 成员内部类
1、成员内部类简介
在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。
在内部类中可以随意使用外部类的成员方法以及成员变量。
成员内部类的语法如下:
public class OuterClass { //外部类
private class InnerClass { //内部类
//...
}
}
public class OuterClass {
innerClass in = new innerClass(); //在外部类实例化内部类对象引用
public void outc() {
in.inf();
} //在外部类方法中调用内部类方法
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();
}
}
例如,在主方法中实例化一个内部类对象。
public class void main(String args[]) {
OuterClass out = new OuterClass();
OuterClass.innerClass in =out.doit();
OuterClass.innerClass in2=out.new innerClass(); //实例化内部类对象
2.内部类向上转型为接口
3、使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。
使用成员内部类时,应该遵循以下原则:
(1)可以有各种修饰符,可以用private、public、protectd、static、final 、abstract等修饰符。
(2)如果有内部类有static限定,就是类级别的,否则为对象级别.类级别可以通过外部类直接访问,对象级别需要先生成外部类的对象后才能访问;
(3)内部类不能同名;
(4)非静态内部类中不能声明任何static成员;
(5)内部类可以互相调用;
public class TheSameName {
private int x;
private class Inner {
private int x = 9;
public void doit (int_x) {
x++; //调用的是形参x
this.x++; //调用内部类的变量x
TheSameName.this.x++; //调用外部类的变量x
}
}
}
7.6.2 局部内部类
局部类不仅可以在类中进行定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类。
interface OutInterface2 {
}
class OuterClass3 {
public OutInterface2 doit (final String x) { //doit()方法参数为final类型
//在doit()方法中定义一个内部类
class InnerClass2 implements OutInterface2 {
InnerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
7.6.3 匿名内部类
匿名类所有实现代码都需要在大括号之间进行编写。语法如下:
return new A() { //A指类名
...//内部类体
};
使用匿名内部类时应该以下原则:
(1)匿名类没有构造方法
(2)匿名类不能定义静态的成员
(3)匿名类不能用private、public、protectd、static、final 、abstract等修饰
(4)只可以创建一个匿名类实例
7.6.4 静态内部类
在内部类前添加修饰符static ,这个内部类就变为静态内部类了。
静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
public class StaticInnerClass {
int x = 100;
static class Inner {
void doitInner() {
//System.out.prinln("外部类"+x); //不能调用外部类的成员变量x
}
}
}
在静态内部类中定义主方法
+ public static void main(String args[]) {
System.out.prinln();
7.6.5 内部类的继承
内部类和其他普通类一样可以被继承,但是继承内部类比继承普通类复杂,需要设置专门的语法来完成。
public class OutputInnerClass extends ClassA.ClassB {
public OutputInnerClass(ClassA a) {
a.super();
}
}
class ClassA {
class ClassB {
}
}
在某个类继承内部类时,必须硬性给予这个类带参数的构造方法,并且该构造方法的参数必须是该内部类的外部类引用。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)