最近博主学习了Java中的基础内容:类、对象以及继承,今天我们来谈谈这方面内容。
如果读者之前学习过C语言,那么本文也可以让你快速了解两者的区别
Java作为一门面向对象设计程序的语言,功能强大而且简单易用,和它有着独特的描述、处理对象的方式脱不了关系,因此掌握类与对象是学习Java语言的基础。
首先,简单来说,对象是具体的事物,类是具有同种特征的一群对象的统称。
例如正在阅读博客的读者就是一个对象,而读者与博主都是人,这里的“人”就是一个类。实际上可以将类看作对象的载体,它定义了对象所具有的功能。
对象具有属性和行为。对一只狗(例如边牧犬)而言,它的属性有:颜色,名称,品种,它的行为有:摇尾巴,睡觉,吃东西。 对象是类的实例。
类更像是某些相同属性或行为的对象的一个模板/蓝图。很显然,一个对象可以属于多个(种)类。类之间也可以并列、包含等。对前文那只边牧来说,它既是狗,也可以是宠物,还可以是动物。
在Java中,我们用关键字class来定义一个类,在eclipse编译器的操作为 File -->New --> Class :
Package——Java包:表示为类的集合,其宗旨是把.java文件(Java源文件), .class 文件以及其他文件(例如,.xml文件,.avi文件,.mp3文件,.txt文件等)有条理地进行一个组织,以供使用,因此在新建工程或项目的同时应该新建一个Package。
定义类的代码格式和C语言中的结构体的定义方法类似,示例如下:
public class Dog {
//属性
String name;
public int age;
//方法
int sleeping(int time) {
*****
}
//get方法用于获取属性
public String getname() {
return name;
}
protected void eating() {
*****
}
}
其中属性相当于C语言中的变量,方法(也就是行为)相当于C语言中的函数。值得注意的是,C语言中的结构体只能含有变量,而Java中的类可以同时含有属性和方法,一个类可以用于任意数量的方法。
“public”——访问修饰符:每个属性和方法都有自己的访问修饰符,访问修饰符有四种:public、private、protected,还有一种不带任何修饰符(default)。访问修饰符的作用这里不做介绍。
“String”——字符串类:Java自带一种名为String的类,我们可以将其视为一种字符串的数据类型,不需要像C语言中char a[]那样定义字符串。
对象是类的具体化,想要使用类中的属性或方法就要创建并初始化对象,格式为:类名 对象名 = new 类名()
以下是创建对象的示例代码:
public class Dog {
//属性
public String name;
//主函数
public static void main(String []args) {
Dog doggy = new Dog();
}
}
要访问一个对象的属性和方法,我们可以用"."表示:
//主函数
public static void main(String []args) {
Dog doggy = new Dog();
doggy.name = "candy";
System.out.println("我的狗名字叫"+getName());
//System.out.println为打印语句
}
运行结果如下:
我的狗名字叫candy
类与类之间也可以互相调用,前提是需要在其中调用类中创建被调用的类的对象。在定义过上文Dog类的基础上我们再定义一个PrintName类:
public class PrintName {
public void prName(Dog doggy){//传入Dog类型
System.out.println("2 我的狗名字叫"+doggy.getName());
}
}
可以发现,PrintName类中prName的方法传入了Dog类参数。
之后在main函数添加两行代码:
public static void main(String []args) {
Dog doggy = new Dog();
doggy.name = "candy";
System.out.println("我的狗名字叫"+doggy.getName());
PrintName doggy2 = new PrintName();
doggy2.prName(doggy);
}
运行结果如下:
我的狗名字叫candy
2 我的狗名字叫candy
C语言中没有继承,继承是Java多态性的体现。
从程序员的角度看,继承的双方存在着一种包含关系:被继承的类包含着继承的类,因此我们把前者称为父类,后者称为子类。
有意思的是,在Java中,我们新定义的类都是一个名为“Object”类的子类,因此Object是所有类的父类,所有类在定义时自动继承Object。
继承字面上的意思就是接受父类的,但实际上在Java中继承更多的意义是父类的属性和方法还可以在子类中重新定义(修改或新增)。
类的继承在Java中的表示十分简单,在定义类时,将格式写为“class 子类名 extends 父类名”即可,代码示例如下:
public class BorderCollie extends Dog {//边牧犬类
public String color;
public String getColor(){
return color;
}
public String getName(){
System.out.println("我的狗名字叫"+name);
return name;
}
}
我们定义了一个"边牧"类继承了"犬"类,同时还添加了一个color属性,一个getColor方法,并且重新定义了父类中getName的方法。接着我们修改主函数:
public static void main(String []args) {
BorderCollie doggy = new BorderCollie();
doggy.name = "candy";
doggy.color = "golden";
System.out.println("我的狗名字叫"+doggy.getName());
System.out.println("我的狗颜色是"+doggy.color);
}
得到结果:
我的狗名字叫candy
我的狗名字叫candy
我的狗颜色是golden
如果此时我们想在子类中调用父类中的getName,可以使用关键字super,格式为“super.方法名”,修改子类中的方法:
public String getName(){
System.out.println("我的狗名字叫"+name);
return (super.getName);
}
运行结果与之前保持一致:
我的狗名字叫candy
我的狗名字叫candy
我的狗颜色是golden
当然,我们可以继续再定义一个candy类来继承BorderCollie类,这种操作叫多层继承。但是值得注意的是,Java不允许一个类多继承父类。即以下代码在Java中不成立:
public class BorderCollie extends Dog,printName {
}
大部分情况,方法所接受的参数的数据类型和输入的数据类型是不匹配的,理论上会引发报错:
public class printName {
public void prName(Dog doggy){
System.out.println("我的狗名字叫"+doggy.getName());
}
}
public class Dog{
//属性
public String name;
//方法
public String getName(){
return name;
}
public void sleep() {
System.out.println("我的狗睡了4小时");
}
//主函数
public static void main(String []args) {
BorderCollie doggy = new BorderCollie();
doggy.name = "candy";
printName name = new printName();
name.prName(doggy);
}
}
public class BorderCollie extends Dog{
public String color;
}
示例中 name.prName(doggy) 语句输入的参数doggy是BorderCollie类型,与需要输入的Dog类型不相同,但实际上程序能够继续运行:
我的狗名字叫candy
这就是子类继承父类时自动转型的优点。因此在Java中,子类可以作为任意父类的类型被当做参数输入到方法当中,这样就大大增加了兼容性。同时对于特殊父类Object,我们定义的类可以使用Object当中任意一种方法:
类的继承的缺点很明显,无法多继承导致有时无法对多个父类进行整合,接口的出现就是为了实现多继承。实现接口的方法和继承相同,只需把extens关键字改为implements,但是在使用之前,我们需要用interface,在类之外,创建一个含有“空”方法的接口,使用方法如下:
interface sleeping{ //实现狗狗睡觉的接口
void sleep(int time); //实现狗狗睡觉的方法(在接口里是空的)
}
public class Dog {
public String name;
public String getName(){
return name;
}
public void sleep(int time) {
System.out.println("我的狗睡了"+time+"小时");
}
//主函数
public static void main(String []args) {
BorderCollie doggy = new BorderCollie();
doggy.sleep(2);
}
}
示例表明接口继承之后需要在类中重新定义同名方法(包括参数和返回值)。运行结果如下:
我的狗睡了2小时
当然,只继承一个无法体现接口多继承的特性,我们再添加一个接口:
interface sleeping{ //实现狗狗睡觉的接口
void sleep(int time); //实现狗狗睡觉的方法(在接口里是空的)
}
interface sleeping3h{//实现狗狗固定睡3小时的接口
void sleep();
}
public class Dog implements sleeping,sleeping3h{
//属性
public String name;
//方法
public String getName(){
return name;
}
public void sleep(int time) {
System.out.println("我的狗睡了"+time+"小时");
}
public void sleep() {
System.out.println("我的狗睡了3小时");
}
//主函数
public static void main(String []args) {
BorderCollie doggy = new BorderCollie();
doggy.sleep(2);
doggy.sleep();
}
}
运行结果符合预期:
我的狗睡了2小时
我的狗睡了3小时
如果继承的接口当中有完全重复的方法,那么编译器会报错:
当然我们还有解决方案:
interface sleeping{
default void sleep() {
System.out.println("我的狗睡了2小时");
}
}
interface sleeping3h{
default void sleep() {
System.out.println("我的狗睡了3小时");
}
}
public class Dog implements sleeping,sleeping3h{
//属性
public String name;
//方法
public String getName(){
return name;
}
public void sleep() {
sleeping.super.sleep();
sleeping3h.super.sleep();
System.out.println("我的狗睡了4小时");
}
//主函数
public static void main(String []args) {
BorderCollie doggy = new BorderCollie();
doggy.sleep();
}
}
我的狗睡了2小时
我的狗睡了3小时
我的狗睡了4小时
运行结果表明,用default关键字加上"接口名.super.方法名"的形式即可准确调用不同接口中的同名方法。
以上就是今天要讲的内容,本文不仅介绍了Java语言中类和对象的使用、及类的继承和接口继承,而且介绍了C和Java语法的部分区别,并且讲述了他们出现的原因。