Java是一门面向对象非常好的语言,拥有面向对象的三个基本特征:封装、继承、多态。
封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
1. 将类的某些信息隐藏在类的内部,不允许外部程序直接访问;
2. 通过该提供的方法来实现对隐藏信息的操作和访问;
1. 修改属性为私有设为private;
2. 创建getter和setter方法,设为public用于属性的读写;
3. 在gettter和setter方法中加入属性控制语句,用于对属性的合法进行判断;
1. 封装一个学生类
public class Student {
private String name;
private int age;
// 获取学生姓名
public String getName() {
return name;
}
// 设置学生姓名
public void setName(String name) {
this.name = name;
}
// 获取学生年龄
public int getAge() {
return age;
}
// 设置学生年龄
public void setAge(int age) {
this.age = age;
}
// 无参构造函数
public Student(){
}
// 有参构造函数
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
2. 调用学生类实例化对象
public class StudentTest {
public static void main(String[] args){
// 实例化一学生
Student student = new Student();
// 设置学生姓名
student.setName("aiguangyuan");
// 设置学生年龄
student.setAge(30);
}
}
继承是面向对象的三大特性之一,可以使子类具有父类的属性和方法,还可以在子类中重新定义、追加属性和方法。当多个类中存在相同的属性和方法,使用继承模式将每个子类相同代码直接抽取出来放到父类中。
1. 父类:也被称为基类、超类
package aiguangyuan.test;
public class Parent {
protected String name;
protected int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2. 子类:也被称为派生类
package aiguangyuan.test;
public class Son extends Parent{
public void work(){
System.out.println("我是"+this.name+",今年"+this.age+"岁,我正在写代码");
}
}
3. 写一个类进行测试
package aiguangyuan.test;
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.setAge(20);
son.setName("Mark");
int age = son.getAge();
String name = son.getName();
System.out.println(age);
// 20
System.out.println(name);
// Mark
son.work();
// 我是Mark,今年20岁,我正在写代码
}
}
1. 继承的优点
提高了代码的复用性,多个类相同的成员属性和方法可以放到一类中;
提高了代码的复用性,如果方法的代码需要修改,只需修改一处即可;
2. 继承的缺点;
继承让类与类之间产生了关系,类的耦合性也增加了,当父类发生变化时,子类也不得不跟着变化,削弱了子类的独立性;
1. 首先在子类局部范围中查找;
package aiguangyuan.test;
public class Son extends Parent{
public int age = 20;
public void show(){
int age = 22;
System.out.println("当前的年龄为:"+age);
// 当前的年龄为:22
}
}
2. 如果子类局部范围中查找没有,就在子类成员范围查找;
package aiguangyuan.test;
public class Son extends Parent{
public int age = 20;
public void show(){
// int age = 22;
System.out.println("当前的年龄为:"+age);
// 当前的年龄为:20
}
}
3. 如果在子类局部范围和子类成员范围查找都没有,就在父类成员查找;
父类代码:
package aiguangyuan.test;
public class Parent {
public int age = 18;
public int height = 175;
public int weight = 120;
}
子类代码:
package aiguangyuan.test;
public class Son extends Parent{
// public int age = 20;
public void show(){
// int age = 22;
System.out.println("当前的年龄为:"+age);
// 当前的年龄为:18
}
}
4. 子类局部范围中访问子类成员范围使用this;
package aiguangyuan.test;
public class Son extends Parent{
public int age = 20;
public void show(){
int age = 22;
System.out.println("当前的年龄为:"+this.age);
// 当前的年龄为:20
}
}
5. 子类局部范围中访问父类成员范围使用super;
父类代码:
package aiguangyuan.test;
public class Parent {
public int age = 18;
public int height = 175;
public int weight = 120;
}
子类中使用父类成员:
package aiguangyuan.test;
public class Son extends Parent{
public int age = 20;
public void show(){
int age = 22;
System.out.println("当前的年龄为:"+super.age);
// 当前的年龄为:18
}
}
子类中所有的构造方法默认都会访问父类中的无参构造方法。
因为子类会继承父类中的数据,所以子类初始化之前,需要对父类进行初始化。
每个子类构造方法的第一句默认都是super()。
如果父类中没有无参构造方法,只有带参构造方法,怎么办?
1. 父类中自己单独定义一个无参构造方法;
2. 通过super关键字显示调用父类的有参构造方法;
父类如下:
package aiguangyuan.temp;
public class Parent {
// 父类中没有无参构造方法
public Parent(int age){
System.out.println("父类中的有参构造方法,参数为:"+age);
}
}
子类如下:
package aiguangyuan.temp;
public class Son extends Parent{
public Son(){
// 父类中没有无参构造函数,通过super调用父类有参构造函数
super(48);
System.out.println("儿子类的无参构造方法");
}
public Son(int age){
// 父类中没有无参构造函数,通过super调用父类有参构造函数
super(48);
System.out.println("儿子类的有参构造方法,参数为:"+age);
}
}
1. 首先在子类范围中查找;
package aiguangyuan.study;
public class Son extends Parent {
public void study(){
System.out.println("我是儿子,我很热爱学习");
}
}
以上是一个儿子类,他继承了父类,里面有一个study方法。
package aiguangyuan.study;
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.study();
// 我是儿子,我很热爱学习
}
}
当实例化儿子对象时,调用study方法,首先调用儿子类里面的study方法。
2. 如果在子类中查找没有,就在父类成员查找;
父类如下:
package aiguangyuan.study;
public class Parent {
public void study(){
System.out.println("我是父亲,我很热爱学习");
}
}
子类如下:
package aiguangyuan.study;
public class Son extends Parent {
}
结果如下:
package aiguangyuan.study;
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.study();
// 我是父亲,我很热爱学习
}
}
3. 如果父类和子类中都没有则会报错;
1. this代表本类对象的引用;
2. super代表父类存储空间的标识,可以理解为父类对象的引用;
当子类中出现了和父类一模一样的方法,该方法中需要父类的功能,而又有自己独特的内容,这样就可以通过覆写父类的方法,这样既延续了父类的功能,又定义了自己的内容。
父类如下:
package aiguangyuan.temp;
public class Phone {
public void call(String name){
System.out.println(name+"手机可以拨打电话");
}
}
子类如下:
package aiguangyuan.temp;
public class NewPhone extends Phone{
@Override // 此注解代表覆写
public void call(String name){
System.out.println("华为手机支持视频通话");
super.call(name);
}
}
结果如下:
package aiguangyuan.temp;
public class TestPhone {
public static void main(String[] args) {
NewPhone newPhone = new NewPhone();
newPhone.call("诺基亚");
// 华为手机支持视频通话
// 诺基亚手机可以拨打电话
}
}
方法重写注意事项:
1. 私有的方法不能被重写,因为父类中的私有方法子类不能被继承;
2. 子类方法访问权限不能比父类低,可以大于也可以等于,其中公有大于默认,默认大于私有;
Java中有四种权限修饰符,其中三种有访问权限修饰符,分别为private、public和protected,还有一种不带任何修饰符。
1. private:Java语言中对访问权限限制最窄的修饰符,一般称之为私有的。被其修饰的的类、属性及方法只能被该类的对象访问,其子类不能访问,更不允许跨包访问;
2. default:即不加任何访问修饰符,通常称为默认访问模式。该模式下,只允许在同一个包中进行访问;
3. protect:介于public和private之间的一种访问修饰符,一般称之为保护模式。被其修饰的类、属性及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问;
4. public:Java中访问限制最宽的修饰符,一般称之为公有的。被其修饰的类、属性及方法不仅可以跨类该问,还可以跨包访问;
在C++语言中,是可以同时继承两个父类的,但是在Java中只支持单继承,如果要继承两个父类,需要分两次分别继承,即多层继承。
多态是面向对象的三大特征之一,即同一个对象,在不同的时刻表现出来不同的形态。
1. 有继承或实现的关系;
2. 子类有对父类的方法进行重写;
3. 父类的引用来自子类对象;
父类代码:
package aiguangyuan.temp;
public class AnimalParent {
public void eat(){
System.out.println("这是动物父类中的吃方法");
}
}
子类代码:
package aiguangyuan.temp;
public class Dog extends AnimalParent{
@Override
public void eat(){
System.out.println("狗类重写了父类的吃方法");
}
}
多态实现:
package aiguangyuan.temp;
public class AnimalDemo {
public static void main(String[] args) {
// 子类的引用来自子类
// Dog dog = new Dog();
// dog.eat();
// 父类的引用来自子类
AnimalParent animalParent = new Dog();
animalParent.eat();
// 狗类重写了父类的吃方法
}
}
成员变量:编译看左边,执行看左边;
成员方法:编译看左边,执行看右边;
为什么成员变量和成员方法的访问不一样呢?
这是因为成员方法有重写,而成员变量是没有的。
父类代码:
package aiguangyuan.test;
public class AnimalParent {
public int age = 40;
public void eat(){
System.out.println("我是动物父类中的吃方法");
}
}
子类代码:
package aiguangyuan.test;
public class Dog extends AnimalParent{
public int age = 20;
public int weight = 40;
@Override
public void eat() {
System.out.println("我是狗类中的吃方法");
}
public void show(){
System.out.println("当前显示的是狗类");
}
}
执行示例:
package aiguangyuan.test;
public class AnimalDemo {
public static void main(String[] args) {
AnimalParent animalParent = new Dog();
// System.out.println(animalParent.weight);
// 编译报错,因为左边的animalParent没有wight属性,所以也无法执行
// animalParent.show();
// 编译报错,因为左边的animalParent没有show方法
animalParent.eat();
// 执行成功,因为右边的Dog类中有eat方法
}
}
多态的好处:提高了程序的扩展性。
具体的体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参操作。
定义动物父类:
package aiguangyuan.test;
public class AnimalParent {
public void eat(){
System.out.println("我是动物父类中的吃方法");
}
}
定义子类的狗类:
package aiguangyuan.test;
public class Dog extends AnimalParent{
@Override
public void eat() {
System.out.println("我是狗类,我在吃屎");
}
}
定义子类的猫类:
package aiguangyuan.test;
public class Cat extends AnimalParent{
@Override
public void eat() {
System.out.println("我是猫类,我在吃鱼");
}
}
定义动物的操作类:
package aiguangyuan.test;
public class AnimalOperate {
//public void useCatEat(Cat cat){
// cat.eat();
//}
//public void useDogEat(Dog dog){
// dog.eat();
//}
//
// 定义方法的时候,使用父类型作为参数,
public void useAnimal(AnimalParent animalParent){
animalParent.eat();
}
}
执行示例:
package aiguangyuan.test;
public class AnimalDemo {
public static void main(String[] args) {
// 调用动物操作类
AnimalOperate animalOperate = new AnimalOperate();
// 调用猫类中的useCatEat方法
//animalOperate.useCatEat(new Cat());
// 我是猫类,我在吃鱼
// 调用狗类中的useDogEat方法
//animalOperate.useDogEat(new Dog());
// 我是狗类,我在吃屎
// 在使用的时候,使用具体的子类型参操作。
animalOperate.useAnimal(new Cat());
// 我是猫类,我在吃鱼
animalOperate.useAnimal(new Dog());
// 我是狗类,我在吃屎
}
}
多态的弊端:不能使用子类的特有功能。
1. 向上转型,从子类到父类,父类引用指向子类对象,也是Java中默认的存在方式;
2. 向下转型,从父类到子类,父类引用转为子类对象,这种方式只能显示的强转;
定义父类:
package aiguangyuan.test;
public class AnimalParent {
public void eat(){
System.out.println("我是动物父类中的吃方法");
}
}
定义子类狗类:
package aiguangyuan.test;
public class Dog extends AnimalParent{
@Override
public void eat() {
System.out.println("我是狗类,我在吃屎");
}
public void showDog(){
System.out.println("我是小狗");
}
}
执行示例:
package aiguangyuan.test;
public class AnimalDemo {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.showDog();
// 我是小狗
// 多态中,编译阶段是看左边,执行是看右边,向上转型,从子到父
AnimalParent parent = new Dog();
// parent中没有showDog方法,如果想调用该方法需要向下转型,从父到子
Dog dog2 = (Dog) parent;
dog2.showDog();
// 我是小狗
}
}