java面向对象(核心技术)

1.类的封装

封装是面向对象编程的核心思想,封装的载体是类,且对象的属性和行为被封装在这个类中。

下面举个例子,一个与服务员交互的例子,比如我们去一个KTV唱歌,我们首先交互对象肯定是服务员,然后由服务员给顾客提供开包间服务,我们把包间封装成一个类(Room),在创建一个服务员类(Waiter),由服务员去引导顾客,代码如下:

包间类(Room)代码:

public class Room {
	public void Small() {
		System.out.println("小包套餐2-4(人):果盘一个,啤酒6瓶;售价:128元");
	}
	public void Medium() {
		System.out.println("中包套餐5-8(人):果盘一个,零食2包,啤酒12瓶;售价:258元");
	}
	public void Big() {
		System.out.println("大包套餐9-15(人):果盘一个,花生瓜子1盘,零食4包,啤酒24瓶;售价:368元");
	}
}

服务员类(Waiter)代码:

import java.util.Scanner;

public class Waiter {
	public static void main(String[] args) {
		//创建包间类
		Room PrivateRoom = new Room();
 		Scanner sc = new Scanner(System.in);
		System.out.print("您好,欢迎观临xxxxxKTV,我们有大中小包间,您需要哪种呢:(大/中/小)");
		//控制台输入的内容
		String confirm = sc.next();
		if(confirm.equals("大")) {
			//调用Room类中的大包间方法
			PrivateRoom.Big();
		}else if(confirm.equals("中")) {
			//调用Room类中的中包间方法
			PrivateRoom.Medium();
		}else if(confirm.equals("小")){
			//调用Room类中中的小包间方法
			PrivateRoom.Small();
		}	
	}
}

返回结果:

aaa

从这个例子看出,先由顾客和服务器交流,在确定顾客想要哪种包间,整个交流过程中,顾客和包间直接是透明的,作为顾客,不知道包间的价钱如何,这种编程模式就是封装。

2.类的继承

继承的基本思想是基于某个父类的扩展,并制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类中的某些方法。

在java中,让一个类继承另一个类需要使用extends关键字,语法如下:

Subclass  extends Parentclass

Subclass子类继承了父类Parentclass类的同时,也继承了父类Parentclass类中的属性和方法。

注意:java仅支持单继承,即一个只可以有一个父类。

下面举一个简单的例子,代码如下:

父类(Parentclass)代码:

public class Parentclass {
	String parent = "我是父类成员变量";
	public String Parent(String parent1) {
		return parent1;
	}
}

子类(Subclass)代码:

public class Subclass extends Parentclass {
	String sub = "我是子类成员变量";
	public static void main(String[] args) {
		//创建父类对象
		Parentclass parentclass = new Parentclass();
		//创建子类对象
		Subclass subclass = new Subclass();
		//输出父类成员变量
		System.out.println(parentclass.parent);
		//输出子类成员变量
		System.out.println(subclass.sub);
		//子类调用父类方法
		System.out.println(parentclass.Parent("我是子类,我调用的是父类的方法"));
	}
}

返回结果:

我是父类成员变量
我是子类成员变量
我是子类,我调用的是父类的方法

从这个结果可以看出,子类继承了父类,虽然没有定义子类任何成员方法,但仍可以调用父类的方法,被调用的方法就是从父类那里继承过来的。

3.方法的重写

父类的成员都会被子类继承,当父类中的某个方法并不适用于子类时,就需要在子类中重写父类的这个方法。

继承并不只是扩展父类的功能,还可以重写父类的成员方法,重写(还可以称为覆盖)就是在子类中将父类的成员方法名称保留,重新编写父类成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型(重写父类成员方法的返回值类型是基于java SE 5.0版本以上编译器提供的新功能)。

在继承中还有一种特殊的重写方式,子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现的内容,这种特殊的重写方式被称为重构。

注意:当重写父类方法时,修改方法的修饰权限只能从小的范围到大的范围改变,例如,父类中A方法的修饰权限为protected,继承之后子类的方法A的修饰权限只能修改为public,不能修改为private。

以下是方法重写的例子,代码如下:
 

//----------------父类-----------------
public class Parentclass {
	public String Parent() {
		return "我是父类方法1";
	}
}


//---------------子类-------------------
public class Subclass extends Parentclass {
	//重写父类方法
	public String Parent() {
		return "我是父类方法2";
	}
	public static void main(String[] args) {
		//创建父类对象
		Parentclass parentclass = new Parentclass();
		//创建子类对象
		Subclass subclass = new Subclass();
		//输出子类和父类方法
		System.out.println(parentclass.Parent());
		System.out.println(subclass.Parent());
	}
}

返回结果:

我是父类方法1
我是父类方法2

super关键字

如果子类重写了父类的方法,就再也无法调用到父类的方法吗?如果想在子类的方法中实现父类原有的方法怎么办?为了解决这种需求,java提供了super关键字,super关键字代表父类对象,super关键字的使用方法如下:

super.属性

super.方法()

以下是super关键字的例子,代码如下:

//----------------父类-----------------
public class Parentclass {
	public String Parent() {
		return "我是父类方法1";
	}
}


//---------------子类-------------------
public class Subclass extends Parentclass {
	//重写父类方法
	public String Parent() {
		//调用父类方法并添加字符串
		return super.Parent() + ",我又加了几个字符串";
	}
	public static void main(String[] args) {
		//创建父类对象
		Parentclass parentclass = new Parentclass();
		//创建子类对象
		Subclass subclass = new Subclass();
		//输出子类和父类方法
		System.out.println(parentclass.Parent());
		System.out.println(subclass.Parent());
	}
}

返回结果:

我是父类方法1
我是父类方法1,我又加了几个字符串

4.方法重载

构造方法的名称由类名决定。如果以不同的方式创建某个类的对象,那么就需要使用多个形参不同的构造方法来完成,为了让这些方法名相同但形参不同的构造方法同时存在,必须用到方法重载,虽然方法的重载起源于构造方法,但是他也可以应用到其他方法中,方法的重载就是在同一个类中允许同时存在多个同名的方法,只要这些方法的参数个数或类型不同即可。

以下是方法重载的例子,代码如下:


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(double a, int b) {
		return (int) (a + b);
	}

	// 定义不定长参数
	public static int add(int... a) {
		int s = 0;
		// 根据参数个数循环操作
		for (int i = 0; i < a.length; i++) {
			s += a[i];// 将每个参数的值相加
		}
		return 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));
	}
}

返回值:

调用add(int)方法:1
调用add(int,int)方法:3
调用add(double,double)方法:5.4
调用add(int a, double b)方法:4
调用add(double a, int b) 方法:5
调用add(int... a)不定长参数方法:45
调用add(int... a)不定长参数方法:9

说明:

  • 前两个方法的参数个数不同,所以构成了重载关系;
  • 前两个方法与第3个方法比较时,方法的参数类型不同,并且方法的返回值类型也不同,所以这3个方法也构成了重载关系;
  • 比较第4、5两个方法时,会发现除了参数的出现顺序不同之外,其他都相同,这样同样可以根据这个区别将两个方法构成重载关系;
  • 而最后一个使用不定长参数的方法,实质上与参数数量不同是一个概念,也构成了重载;

5.向上转型

在java中,对象类型的转换包括向上转型与向下转型,例如,猫是动物,也就是说猫是动物的一种,那么久可以将猫对象看作是一个动物对象

下面例子是向上转型的用法,代码如下:

//----------------Animals类--------------
public class Animals {
	public Animals(String name) {
		System.out.println("我是只" + name);
	}
}


//--------------Demo类--------------------
public class Demo extends Animals {
	String str = "猫";
	public static void main(String[] args) {
		//向上转型
		Animals An = new Demo();
		//将子类对象的属性str赋予父类对象
		An.Animalsname(name.str);
		
	}
}

返回结果:

我是只猫

在以上代码中,Demo继承了动物类(Animals),动物类存在一个Animalsname方法,他的参数是str(猫),而在Demo主方法中调用Animalsname方法时传入的参数却是参数str(猫),这里可以看出,猫是一个动物,所以可以将猫的对象看作是一个动物对象,即把子类对象赋值给父类类型的对象,这种技术被称为向上转型。

常规的继承都是将顶级类设置在页面的顶部,然后逐渐向下,所以将子类对象看作是父类对象被称为向上转型。由于向上转型是从一个较具体的类到抽象类的转换,所以向上转型是安全的,例如,可以说猫是一种动物,但不能说动物就是猫。

 6.向下转型

通过向上转型可以推理处向下转型是将较抽象类转换为较具体的类,这样的转型通常会出现问题,例如,不能说四边形是平行四边形,也不鞥说所有的鸟都是鸽子,因为这些都不符合逻辑。

修改上面的代码如下:

//----------------Animals类--------------
public class Animals {
	public Animals(String name) {
		System.out.println("我是只" + name);
	}
}


//--------------Demo类--------------------
public class Demo extends Animals {
	String str = "猫";
	public static void main(String[] args) {
		//向上转型
		Animals An = new Demo();
		//向下转型
		Demo name = (Demo)An;
	}
}

注意:父类对象要变成子类的对象,必须通过显示类型转换才能实现,例如上面代码中(Demo)An,子类必须用小括号括起来

7.instanceof关键字

当在程序中执行向下转型时,如果父类对象不是子类的实例,就会发生ClassCastException异常,所以在执行向下转型之前需要使用instanceof关键字判断父类是否为子类的实例,instanceof关键字嗨可以判断某个类是否实现了某个接口,instanceof关键字语法如下:

myobject instanceof ExampleClass

  • myobject:某类的对象引用
  • ExampleClass:某个类

使用instanceof关键字的表达式返回值为布尔值,如果返回值为true,说明myobject对象为ExampleClass的实例,如果返回值为false,说明myobject不是ExampleClass的实例。

下面以电脑、平板电脑、联想电脑为例,代码如下:

public class Computer {	//电脑
	public static void main(String[] args) {
		//创建电脑对象
		Pad ipad = new Pad();
		//创建平板电脑对象
		LenovoPad lenovoPad = new LenovoPad();
		
		System.out.println("Pad是否继承自电脑?" + (ipad instanceof Computer));
		System.out.println("lenovoPad是否继承自Pad?" + (lenovoPad instanceof Pad));
		System.out.println("lenovoPad是否继承自电脑?" + (lenovoPad instanceof Computer));
		System.out.println("Pad是否继承自lenovoPad?" + (ipad instanceof LenovoPad));
	}
}

class Pad extends Computer{	//平板电脑
	
}

class LenovoPad extends Pad {	//联系电脑
	
}

返回值:

Pad是否继承自电脑?true
lenovoPad是否继承自Pad?true
lenovoPad是否继承自电脑?true
Pad是否继承自lenovoPad?false

8.抽象类与抽象方法

虽然可以使用两组对边分别平行的四边形和有两条边相等的三角形分别定义平行四边形和等腰三角形,但却不能使用具体的语言定义图形,在java中,把类似无法使用具体语言定义的图形类称为抽象类。

在java中,抽象类不能生产对象实例,定义抽象类时,需要使用abstract关键字,定义抽象类的语法如下:

【权限修饰符】abstract class 类名{

                    类体

}

使用abstract关键字定义的类被称为抽象类,使用abstract关键字定义的方法被称为抽象方法,定义抽象方法的语法如下:

【权限修饰符】abstract 方法返回值类型 方法名(参数列表)

从上面的语法可以看出,抽象方法时直接以分号结尾的,没有方法体,抽象方法本身没有任何意义,除非被重写,而承载这个抽象方法的抽象类必须被继承。实际上,抽象类除了被继承之外没有任何意义,下面一张图说明了抽象类的继承关系。

1111111111111

从上图中可以看出,继承抽象类的所有子类都需要重写抽象类中的抽象方法。

注意:构造方法不能定义为抽象方法

下面举个例子,模拟去商场买衣服场景,"去商场买衣服"这句话描述的是一个抽象的行为,到底去哪个商场买衣服,是实体店还是网店,买什么衣服,是短袖、裙子,还是其他的什么衣服?在"去商场买衣服"这句话中,并没有为"买衣服"这个抽象行为指明一个确定的信息,设计一个商场的抽象类,并在其中定义买东西的抽象方法,具体是什么商场、买什么东西,交给子类去实现即可,代码如下:

首先创建一个抽象类和抽象方法抽象成员变量:

public abstract class Market {
	//商场名称
	public	String name;
	//商平名称
	public 	String goods;
	//抽象方法,用来输出信息
	public abstract void shop();
}

在定义一个TaobaoMarket类,继承自Market抽象类,实现其中的shop()抽象方法,代码如下:

public class TaobaoMarket extends Market{
	public void shop() {
		System.out.println(name + "网购" + goods);
	}
}

在定义一个WallMarket类,继承自Market抽象类,实现其中的shop()抽象方法,代码如下:

public class WallMarket extends Market{
	public void shop() {
		System.out.println(name + "实体店购买" + goods);
	}
}

定义一个GoShopping类,在该类中分别使用WallMarket类和TaobaoMarket类创建抽象类的对象,并分别给抽象类中的成员变量赋予不同的值,调用shop()方法分别输出结果,代码如下:

public class GoShopping {
	public static void main(String[] args) {
		//使用派生类对象创建抽象类对象
		Market wall = new WallMarket();
		wall.name = "沃尔玛";
		wall.goods = "七匹狼西服";
		wall.shop();
		//使用派生类对象创建抽象类对象
		Market taobao = new TaobaoMarket();
		taobao.name = "淘宝";
		taobao.goods = "韩都衣舍花裙";
		taobao.shop();
	}
}

返回结果:

沃尔玛实体店购买七匹狼西服
淘宝网购韩都衣舍花裙

综上所述,使用抽象类和抽象方法时,需要遵循以下原则:

  • 在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类;
  • 抽象类不能直接被实例化,即使抽象类中没有声明抽象方法,也不能被实例化;
  • 抽象类被继承后,子类需要重写抽象类中所有的抽象方法;
  • 如果继承抽象类的子类也被声明为抽象类,则可以不用重写父类中所有的抽象方法;

使用抽象类时,可能会出现这样的问题,程序中会有太多重复的代码,同时父类的局限性很大,例如,上面的例子中,也许某个不需要shop()方法,如果将这个shop()方法从父类中拿出,放在别的类里,又会出现新的问题,某些类想要实现"买衣服"场景,竟然需要继承两个父类,java中规定,一个类不能同时继承多个父类,未解决这种问题,接口应运而生

9.接口的声明及实现

接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体,可以将上面图中draw()方法封装到一个接口中,这样可以让一个类技能继承图形吗,又能实现draw()方法接口,这就是接口存在的必要性,各个子类继承图形后使用接口的关系如图:

3333333333333

接口使用interface关键字进行定义,其语法如下:

【修饰符】interface 接口名 【extends 父接口名】{

                   【public】【static】【final】常量;

                   【public】【abstract】方法;

}

  • 修饰符:可选,用于指定接口权限,可选值为public,如果省略则使用默认的访问权限;
  • 接口名:必选参数,用于指定接口的名称,接口名必须是合法的java标识符,一般情况下要求首字符大写;
  • extends父接口名列表:可选参数,用于指定定义的接口继承于哪个接口,当使用extends关键字时,父接口名为必须参数;
  • 方法:接口中的方法都是抽象方法,没有方法体;

一个类实现一个接口可以使用implements关键字,代码如下:

public class Parallelogram implements drawTest {
}

我们举个例子,创建一个类模拟老师和同学交互的过程,在创建两个接口,一个工作接口一个问候接口,代码如下:

首先创建两个接口(Greetings)问候接口和(Working)工作接口

public interface Greetings {
	public abstract void greeting();
}

public interface Working {
	public abstract void working();
}

在创建一个Demo类,来调用刚才创建的两个接口并重写方法,代码如下:

public class Demo implements Greetings,Working{
	//重写Greetings接口抽象方法
	public void greeting() {	
		System.out.println("老师:同学们好");
		System.out.println("同学们:老师好");
	}
	//重写Working接口抽象方法
	public void working() {
		System.out.println("老师:老师开始上课");
		System.out.println("同学们:开始记笔记");
	}
	public static void main(String[] args) {
		//接口也可以进行向上转型操作
		Greetings gt = new Demo();
		Working wk = new Demo();
		//调用抽象方法working、greeting
		gt.greeting();
		wk.working();
	}
}

返回结果:

老师:同学们好
同学们:老师好
老师:老师开始上课
同学们:开始记笔记

注意:在接口中定义的任何变量都自动是static和final的,因此,在接口中定义变量时,必须进行初始化,而且,实现接口的子类不能对接口中的变量重新赋值

10.多重继承

在java中类不允许多重继承,但使用接口可以实现多重继承,因为一个类可以同时实现多个接口,这样可以将多有需要实现的接口放在implements关键字后,并使用英文逗号隔开,但这可能会在一个类中产生庞大的代码量,因为实现一个接口时需要实现接口中的所有方法。在上面的例子老师与学生使用的就是多重继承。

通过接口实现多重继承的语法如下:

class 类 implements 接口1,接口2,接口3.....................

注意:使用多重继承时,可能出现变量或方法名冲突的情况,如果变量冲突,则需要明确指定变量的接口,即通过接口.变量实现,而如果出现方法冲突时,则只要实现一个方法即可。

11.区分抽象类与接口

抽象类和接口都包含可以由子类继承实现的成员,但抽象类时根据源的抽象,而接口时对动作的抽象,抽象类和接口的区别主要有以下几点:

  • 子类只能继承一个抽象类,但可以实现任意多个接口;
  • 接口中的方法都是抽象方法,抽象类可以由非抽象方法;
  • 抽象类中的成员变量可以是各种类型,接口中成员变量只能是静态变量;
  • 抽象类中可以有静态方法和静态代码块,接口不可以;
  • 接口没有构造方法,抽象类可以有构造方法。

综上所述,抽象类和接口在主要成员及继承关系上的不同如下表中所示:
 

               比   较   项                         抽     象     类                          接          口
                    方法                   可以有非抽象方法                所有方法都是抽象方法
                    属性                属性中可以有非静态变量               所有的属性都是静态变量
                 构造方法                        有构造方法                       没有构造方法
                     继承              一个类只能继承一个父类             一个类可以同时实现多个接口
                   被继承              一个类只能继承一个父类            一个接口可以同时继承多个接口
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值