面向对象有4大基本特性:封装、继承、抽象和多态应用面向对象思想编写程序,整个程序的架构既可以变得非常有弹性没有可以减少代码冗余。
类的封装
封装是面向对象变成的核心思想,封装的载体是类,且对象的属性和行为被封装在这个类中。
类的继承
继承的基本思想是基于某个父类的扩展,并制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类中的某些方法。Java中仅支持单继承,即一个类只可以有一个父类。
extends关键字
Child extends Parents
- 1
子类Child类在继承了父类Parents类的同时,也继承了父类Parents类中的属性和方法。
方法的重写
父类的成员都会被子类继承,当父类中的某个方法不适用于子类时,就需要在子类中重写父类的这个方法。
在子类中将父类的成员方法的名称保留,重写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型。
public class Computer {
String screen = "液晶显示屏";
void startup(int a) {
System.out.println("我有" + a + "台" + screen);
}
}
public class Pad extends Computer{
String battery = "500毫安电池";
@Override
void startup(int a) {
super.startup(a);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
方法的重构
在继承中还有一种特殊的重写方式,子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容,这种特殊的重写方式被称为重构。
public class Computer {
String screen = "液晶显示屏";
void startup(int a) {
System.out.println("我有" + a + "台" + screen);
}
}
public class Pad extends Computer{
String battery = "500毫安电池"; // 重构:返回值、方法名称、参数类型及个数完全相同,唯一不同的方法实现内容
@Override
void startup(int a) {
System.out.println("我有" + a + "台" + screen + ",和" + a + "个" + battery);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
注意:重写父类方法时,修改方法的修饰权限只能从小的范围到大的范围改变。
super关键字
Java提供了super关键字,super关键字代表父类对象,super关键字的使用方法如下:
super.property; // 调用父类的属性
super.method; // 调用父类的方法
- 1
- 2
所有类的父类Object类
在Java中,所有的类都直接或间接继承了java.lang.Object类,如String、Integer等类都是继承与Object类,由于所有类都是Object子类,所以在定义类时,省略了extends Obejct语句。
在Obeject类中最常用的两个方法为equals()和toString()还有getClass()方法,由于所有类都是Object类的子类,所以任何类都可以重写Object类的方法。
1、getClass()方法
getClass方法会返回某个对象执行时的Class实例,然后通过getName可以获取类的名称。
getClass().getName();
- 1
2、toString()方法
toString方法会返回某个对象的字符串表示形式。打印某个对象时,会自动调用重写的toString方法。
3、equals()方法
Object类中的equals()方法比较的是两个对象的引用地址是否相等。
类的多态
在Java中,多态的含义是"一种定义,多种实现",类的多态性可以从两方面体现,一是方法的重载,二是类的上下转型。
方法的重载
在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
public class Pad extends Computer{
void startup(int a,int b) {
System.out.println("我有大宝" );
} void startup(int a) {
super.startup(a);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
向上转型
在Java中,把子类对象赋值给父类对象这种技术被称为向上转型。父类对象无法调用子类独有的属性或者方法。
public class Computer {
static void startup(Computer computer) {
System.out.println(computer);
}
}
public class Pad extends Computer{
public static void main(String[] args) {
Pad pc = new Pad();
startup(pc);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
向下转型
将父类对象强制转换为某个子类对象的方式被称为显示类型转换。
public class Pad extends Computer{
public static void main(String[] args) {
Pad pc = new Pad();
startup(pc); Computer computer = new Pad();
// 父类转子类需要(显示类型)强制转换才能实现
Pad pad = (Pad)computer;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
instanceof关键字
当在程序中执行向下转型操作时,如果父类对象不是子类的实例,就会发送ClassCastException异常。所以需要判断父类是否为子类的实例,instanceof可以判断某个类是否实现了某个接口。
public class Computer {
}
public class Pad extends Computer{
public static void main(String[] args) {
Computer computer = new Computer();
// 判断computer是不是Pad的实例
if (computer instanceof Pad) { Pad pad = (Pad)computer; }
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
抽象类与接口
抽象类与抽象方法
抽象类不能产生对象实例,定义抽象类时,需要使用abstract关键字。
权限修饰符 abstract class 类名 {
类体
}
- 1
- 2
- 3
使用abstract定义的方法被称为抽象方法。
权限修饰符 abstract 方法返回值类型 方法名(参数列表);
- 1
抽象方法是直接以分号结尾的,没有方法体,抽象方法本身没有任何意义,除非被重写,而承载这个抽象方法的抽象类必须被继承。继承抽象类的子类需要重写抽象类中的抽象方法。
public abstract class Market {
public String name;
public String goods;
public abstract void shop(); //抽象方法
}
public class TaobaoMarket extends Market{
@Override
public void shop() {
System.out.println(name + "网购" + goods);
} public static void main(String[] args) {
Market market = new TaobaoMarket(); // 派生类对象创建抽象类对象
market.name = "仙宝";
market.goods = "芭比娃娃";
market.shop();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
运行结果: 仙宝网购芭比娃娃
抽象类和抽象方法需要遵循以下原则:
1、抽象类可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须是抽象类。
2、抽象类不能直接被实例化,即使抽象类中没有声明抽象方法。
3、抽象类被继承之后,子类需要重新抽象类中所有抽象方法。
4、如果继承抽象类的子类也是抽象类,则可以不用重写父类中所有的抽象方法。使用抽象类程序中会有太多冗余的代码。一个类不能同时继承多个父类,接口应运而生。
接口的声明及实现
接口是抽象类的延伸,可以将它看作是纯碎的抽象类,接口中的所有方法都没有方法体。
权限修饰符 interface 接口名 {
}
- 1
- 2
一个类实现一个接口可以使用implements关键字
public class Para implements draw {
}
- 1
- 2
在接口中定义的任何变量都自动是static和final的,因此在接口中定义常量时,必须进行初始化,而且实现接口的子类不能对接口中的变量重新赋值。
多重继承
在Java中类不允许多重继承,但是用接口可以实现多重继承,因为一个类可以实现多个接口。
类名 implements 接口1,接口2,接口3 {
}
- 1
- 2
使用多重集成式,可能出现变量或者方法名冲突的情况,如果变量冲突,则需要明确指定变量的接口,即通过 “接口名.变量” 实现,如果方法出现冲突,则只需要实现一个方法即可。
区分抽象类与接口
继承:子类只能继承一个抽象类,但是可以实现多个接口
方法:抽象类可以有非抽象方法,接口都是抽象方法。
属性:抽象类可以为任意类型,接口中只能是静态常量。
代码:抽象类可以有静态方法和静态代码块,接口不可以。
构造方法:抽象类可以有构造方法,接口没有。
访问控制
Java中主要通过访问控制符、类包和final关键字对类、方法或者变量的访问范围进行控制。
访问控制符
把该隐藏的隐藏起来,把该暴露的暴露出来,这两个方面都需要通过"访问控制符"来实现。
本类:一个class文件
同包:一个package包下
子类: 其他包下的子类
其他: 其他包下的非子类
声明类时,如果不使用public修饰符设置类的权限,则默认为default。
Java语言中,类的权限设定会约束类成员的权限设定。例如定义一个default类,不管方法加不加public,他的访问修饰符都是default。
大部分类都使用public,除static或者全局变量以外,属性都使用private。
Java类包
在Java中每定义一个类,通过Java编译器进行编译之后,都会产生一个扩展名为.class的文件,规模主键扩大时,就很容易发生类名冲突。
Java提供了一种管理类文件的机制–类包。在Java中采用类包机制非常重要,类包可以解决类名冲突问题。
Java包的命名规则是全部使用小写字母。如果要使用保重的类,可以使用Java中的import关键字指定。
在使用import关键字时,可以指定类的完整描述,但是为了使用包中更多的类,可以在包名后面加“.*”,这表示在程序中使用包的所有类。当时用import指定的包中类时,并不会指定这个包的子包类,如果用到子类,需要再次引用。
final关键字
final的含义是最后的、最终的,被final修饰的类,方法和变量不能被改变。
1、final类
当某个类设置为final类时,类中方法就会被隐式的设置为final形式,但是final类中的成员变量既可以被定义为final形式,又可以被定义为非final形式。
2、final方法
被final修饰的方法不能被重写,将方法定义为final类型可以防止子类修改该方法的定义与实现方式,同时final方法的执行效率要高于非final方法。子类继承父类时候,父类方法用final修饰之后,子类是不能覆盖的。
3、final变量
final关键字可用于修饰变量,一旦变量被final修饰,就不可以再改变变量的值。通常被final修饰的变量称为常量。final修饰的变量,必须在声明时对其赋值。无论是常量还是被final修饰的对象引用,都不可以重新赋值。
内部类
在类中定义一个类,那么就把在类中定义的类称作内部类。
成员内部类
除成员变量、方法和构造器可作为类的成员外,成员内部类也可以作为类的成员。语法如下:
public class OtherClass { // 外部
public class InnerClass { // 内部
}
}
- 1
- 2
- 3
- 4
- 5
外部类的成员方法和成员变量尽管用private修饰,内部类也可以用。
在外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。
public class OtherClass { // 外部
private String name; public OtherClass(String name) {
this.name = name;
} public void name() {
System.out.println(this.name);
}
public class InnerClass { // 内部
private Integer age; public InnerClass(Integer age) { this.age = age;
}
public void age() { System.out.println(this.age);
}
} public static void main(String[] args) {
OtherClass otherClass = new OtherClass("张三");
otherClass.name();
InnerClass innerClass = otherClass.new InnerClass(22);
innerClass.age();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
内部类对象非常依赖于外部类对象otherClass.new InnerClass(22),除非已经存在一个外部类对象。
匿名内部类
匿名内部类的特点就是只需要使用一次,也就是说,不能被重复使用。最常用的创建匿名内部类的方式是创建某个接口类型或抽象类的对象,语法如下:
new A(){
// 匿名内部类的类体
};
- 1
- 2
- 3
匿名内部类应该遵循以下原则:
1、匿名类没有构造方法。
2、匿名类不能定义静态的成员。
3、匿名类不能使用private、public、protected、static、final、abstract等修饰。
4、只可以创建一个匿名类实例。
public abstract class Market {
public abstract void shop(); //抽象方法
}
public class TaobaoMarket{
public static void main(String[] args) {
new Market() { @Override public void shop() { System.out.println("去超市买东西"); }
}.shop();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
运行结果:去超市买东西
其实匿名内部类和其他类有着相同的内存结构,只不过匿名内部类创建出的对象没有被具体的变量所引用,所以匿名内部类是一次性的。如果创建出的类对象只使用一次,这种场景就可以考虑使用匿名内部类。
文章来源: blog.csdn.net,作者:怪咖软妹@,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_43888891/article/details/113488684