面向对象的三大特征和基本语法
面向对象(二)
一、面向对象三大特征之一:封装
1.简述
-
封装(Encapsulation)是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节(更直白的说是实现高内聚低耦合)
-
访问元素的权限
- public : 它是可以在全局范围(同一个包或者不同的包)里访问
- protected : 它能够在同一个包可以访问,但不同的包,只有继承关系,才能访问
- default(缺省): 只能在同一个包才可以访问
- private : 只能在本类里面才能访问
-
案例
-
输出的结果
5 women nojob
-
当父类属性(成员变量)是私有的 我们就需要借助get和set 方法(才能外部的类调用)
package inher.home.cn; public class ManKind { //成员变量是私有的 private int sex; private int salary; public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public void manOrWoman() { if (sex == 1) { System.out.println("man"); } else if (sex == 0) { System.out.println("women"); } } public void employeed() { if (salary == 0) { System.out.println("no job"); } else if (sex != 0) { System.out.println("job"); } } }
package inher.home.cn; public class Kids extends ManKind { int yearsOld; public void printAge() { System.out.println(yearsOld); } public static void main(String[] args) { Kids someKid = new Kids(); someKid.yearsOld = 5; someKid.setSex(0); someKid.setSalary(0); someKid.printAge(); someKid.manOrWoman(); someKid.employeed(); } }
-
输出的结果
5 women nojob
-
二、面向对象三大特征之二:继承
1、为什么要有继承
-
多个类中存在 相同属性和行为 时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
-
父类
- 将相同的属性及行为抽取到单独类里面,此类称为父类
-
子类
- 多个类无需再定义这属性及行为,只要继承父类即可,此类称为子类
-
子类与父类是什么关系
- 子类是父类的具体的体现
- 例如:水果是父类、 苹果是子类,也就是说苹果是水果的一种
- 子类有多个,父类只有一个
2、语法
public class 子类 extends 父类{ //里面是实现子类的方法 }
-
举例
-
定义一个父类:类名Person
-
定义一个子类: 分别Student、Waiter、Teacher、Conumser
-
代码如下
package demo.cn.com; class Person { String name; int id; int age; public void info() { System.out.println("name=" + name + " id=" + id + " age = "+age); } } class Waiter extends Person { } class Student extends Person { } class Teacher extends Person { } class Consumer extends Person { } public class MainTest { public static void main(String[] args) { Waiter t1 = new Waiter(); t1.name = "张三"; t1.age = 30; t1.id = 1; t1.info(); } }
-
3、继承的特征
a、子类具有继承父类资源
- 如果父类的资源配置private的访问权限,子类无法使用
-
如果父类的资源配置缺省的访问权限,不同的包的子类无法使用,同一
个包的子类可以访问
b、单继承性
-
父类只有一个,但子类可以有多个
c、 所有的类最终都会继承Object
public class MainTest { public static void main(String[] args) { Waiter t1 = new Waiter(); t1.name = "张三"; t1.age = 30; t1.id = 1; t1.info(); //为什么可以直接调用toString,原因是Object类是所有类的 // 最终继承父类,toString就是在Object类定义,子类可以继承下来使用 String str = t1.toString();//为什么可以调用toString方法 System.out.println(str); } }
4、方法的重写
a、概述
-
在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法
的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
b、不允许方法的重写
- static:他是属于类
- final:常量池
- 父类是private :私有方法(子类重写不了)
c、重写方法的规则
-
修饰符的作用范围大小排序:public>protected>缺省>private
-
“两同一小一大”
-
两同:方法名相同,参数列表一致
-
一小:重写方法的返回值数据类型<= 被重写的方法的返回值数据类型
- 返回值数据类型是指子类与父类的范围
-
一大:重写方法的访问权限符范围>=被重写方法的访问权限符范围
public/protected/缺省 (重写方法) 缺省(被重写方法)
public/protected 重写方法 protected(被重写方法)
public 重写方法 public(被重写方法)
不受重写规则的约束 private -
重写:那么大家都静态方法,那么都是非静态方法
-
-
案例
class Animal { //被重写的方法 public String eat() { System.out.println("animal eatting"); return "100"; } } class Cat extends Animal { //重写方法 //两同:方法名相同、参数列表相同 public String eat() { System.out.println("cat eatting thing"); return "100"; } } public class MainTest { public static void main(String[] args) { Cat t = new Cat(); t.eat(); } }
三、Super关键字用法
1、概述
-
通过super关键字,可以在子类访问父类的资源(属性/行为方法)
- 可以在本类调用父类属性
- 可以在本类调用父类行为方法
- 可以在本类调用父类构造器
super的注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能在出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
2、实例
class Person { protected String name = "张三"; protected int age; public String getInfo() { return "Name: " + name + "\nage: " + age; } } class Student extends Person { protected String name = "李四"; public String getInfo() { //return name; return super.name; } public String getSchool() { String info = super.getInfo(); return info + " school"; } } public class TestStudent { public static void main(String[] args) { Student t1 = new Student(); System.out.println(t1.getInfo()); System.out.println(t1.getSchool()); } }
四、调用父类构造器
1、概述
-
当创建一个类的对象时,首先先调用父类构造器,再到子类的构造器
- 原因:当父类的构造器没有写什么构造方法时系统默认执行构造器(指是无参构造) 就是调用super()
2、实例
class A { public A() { System.out.println("A"); } } class B extends A { public B(String name) { System.out.println("B"); } } class C extends B { public C() { //隐藏一段代码 super("gec"); System.out.println("C"); } } public class MainTest { public static void main(String[] args) { C c = new C(); } }
输出结果是 A B C
五、面向对象三大特征之三:多态
1、概述
- 针对不同的类,对同一个行为能作为不同的响应状态
- 不同的类:继承关系/实现关系
- 同一个行为:行为方法
2、多态的体现
-
产生多态行为要有俩个条件:
- ①运行时的数据类型与编译时的数据类型不一致 ② 要有方法重写 ③要有继承关系
-
Java引用变量有两个类型:编译时类型(由声明该变量时使用的类型决定)和运行时类型(由实际赋给该变量的对象决定)。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定(左编译右运行)
-
编译时的数据类型:当程序编译后,此数据类型就确定下来
-
运行时的数据类型:当程序运行时,此数据类型才确定下来
3、编译时多态
- 方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
- 方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态
package demo.cn.com; class Fruit { } class Apple extends Fruit { } class Demo { public static void main(String[] args) { Fruit fruit = new Fruit(); //对象引用本类实例 Apple t = new Apple(); //编译时多态 Fruit fruit1 = new Apple();//运行时多态 } }
4、多态机制
-
本质
-
能够根据运行时的数据类型,在运行时刻,判断具体调用那个行为方法
①多态机制是针对 行为方法 起作用 ②对属性是不起作用的package demo.cn.com; class ParentCls { public int a = 10; public void info() { System.out.println("parent cls info"); } } class SubCls extends ParentCls { public int a = 20; public void info() { System.out.println("sub cls info"); } } class Asia { public String name = "亚洲人"; public void info() { System.out.println("我是亚洲人"); } } class Chinese extends Asia { public String name = "中国人"; public void info() { System.out.println("我是中国人"); } } public class Demo { public static void main(String[] args) { //SubCls t1=new SubCls(); //编译时的数据是ParentCls,先调用父类方法,运行时数据是在对父类方法进行重写 ParentCls t1 = new SubCls(); //1、编译时的数据类型与运行时的类型不一致 //2、存在方法重写 //启动“多态”机制 System.out.println(t1.a); //打印输出: 10 (调用父类属性值) t1.info(); //打印输出:sub cls info Asia r = new Chinese(); Chinese r2 = new Chinese(); r.info();//打印输出“我是中国人” System.out.println(r.name);//输出亚洲人 Chinese r3 = new Asia(); // error 这个会报错 // 为什么会报错,就这么说 Chinese子类是继承父类的, // 就不能(小的包含大的)只有大的包含小的吧 } }
-
5、多态的应用实例
-
父类作为方法形参,子类的引用变量作为实参,在调用运行时刻,
根据实现的实参子类方法调用
6.多态总结
- 多态机制启动的条件
- 编译时的数据类型与运行时的数据类型不一致,但它们之间存在继承/实现关系
- 存在“重写方法”
- 多态机制只作用“行为方法”,针对成员变量不起作用
- 多态机制作用:增强代码的兼容性
六、instanceof 操作符
1、简介
-
可以通过此操作符,判断子类是否属于父类,如果属于,则返回true,
否则返回false
2、作用
-
强制类型转换之前的判断
举例
package demo.cn.com; class A { public int c = 10; } class B extends A { public int c = 20; } public class MainTest { public static void info(A a) { //强制转换成B类型,明确告诉给jvm,我就是一个B类对象 //隐藏一个程序异常(Exception) if (a instanceof B) { int c = ((B) a).c; System.out.println(c); } } public static void main(String[] args) { //创建B对象 B b = new B(); A a = new A(); info(b); System.out.println("hello" instanceof String); System.out.println("hello" instanceof Object); System.out.println(b instanceof B); System.out.println(b instanceof A); System.out.println(a instanceof B); } }
案例二、
新建一个父类Person 俩个子类(Student、Teacher)
第一个报错的原因:Person 跟 String 都是object类下的,但是他们是属于同一个段位的,也没有继承关系
第二个报错的原因:student跟teacher 都是子类,不存在继承关系;
第三个报错原因:student跟String 存在大小关系,但是不存在继承关系
输出的答案 true true true false false ---------------------- true true true false ------------------------- true true true
七、强制类型转换
- 明确告诉给jvm,是什么数据类型,其实也是判断是否存在继承以及父子关系
if(变量 instanceof 数据类型){ ((数据类型)变量).属性/行为 }
public static void info(A a){ //强制转换成B类型,明确告诉给jvm,我就是一个B类对象 //隐藏一个程序异常(Exception) if(a instanceof B){ int c=((B)a).c; System.out.println(c); } }
-
案例
package demo.cn.com; public class Demo { public static void printInfo(Object o) { //判断此引用变量是否属于String类型 if (o instanceof String) { //强制类型转换成String类型 String msg = (String) o; System.out.println(msg); } } public static void main(String[] args) { printInfo("helloworld"); printInfo(new MainTest()); } }
八、初始化块
- 目的是:对类跟对象进行初始化
- 修饰符:static/缺省
1、初始化块触发的条件
-
针对非静态初始化块:当创建对象(new一个对象)会触发,它触发时
间比构造器还早 -
针对静态初始化块:当类加载到内存,就会触发,只会加载一次
package day20.com.cn.demo; class Student{ { System.out.println("hello world"); } static { System.out.println("hi hello world"); } } public class DemoTest { public static void main(String[] args) { new Student(); System.out.println("--------------"); new Student(); } }
输出的结果
hi hello world
hello world
hello world
2、初始化块访问成员变量
-
非静态初始化块是否可以直接访问成员变量?
-
非静态初始化块它是可以直接访问成员变量,但跟它的摆放位置有
关系,如果非静态初始化块它是放在成员变量之后,则可以直接访
问,否则不能直接访问,如果要强制访问此变量,则必须添加this
关键字,此时变量值为未初始化数据值
-
非静态初始化块它是可以直接访问成员变量,但跟它的摆放位置有
-
静态初始化块是否可以访问静态变量?
-
静态初始化块它是可以直接访问类变量,但跟它的摆放位置有关
系,如果静态初始化块它是放在类变量之后,则可以直接访问,否
则不能直接访问,如果要强制访问此类变量,则必须添加类.类变
量,此变量值为未初始化值数据值
-
静态初始化块它是可以直接访问类变量,但跟它的摆放位置有关
3、静态代码块与普通代码块的执行顺序
-
① 静态代码块>普通代码块 >构造方法(一般情况)
-
②当在父类和子类中:父类static静态代码块>子类static静态代码块>父类的普通代码块>父类构造方法>子类的普通代码块>子类构造方法
-
案例一
package staticTest.demo.cn; import java.util.HashMap; class X { static Y b = new Y(); X() { System.out.print("X"); } { System.out.print("A"); } static { System.out.print("A++"); } } class Y { Y() { System.out.print("Y"); } { System.out.print("B"); } static { System.out.print("B++"); } } public class MainTest extends X { static Y y = new Y(); MainTest() { System.out.print("Z"); } { System.out.print("C"); } static { System.out.print("C++"); } public static void main(String[] args) { /*创建MainTest对象的执行步骤: 1、父类的成员变量初始化(有静态的话,静态优先) 2、父类的构造器 3、本类的成员变量初始化 4、本类的构造器*/ new MainTest(); System.out.println("\n------"); // new MainTest(); } }
输出结果:
-
案例二
根据上面的代码(不修改)我在添加new MainTest();
为什么在次运行这个对象,值就不同了
原因是:静态变量只能运行一次,再次运行时,静态变量就不会在执行了
九、final关键字
-
在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终”。(当修饰类时是无法继承的)
-
当定义变量的是用final 修饰时候,第二次赋值的值对final的值是没有影响的
-
final修饰的成员变量:①直接赋值 ②初始化块
-
final修饰的静态成员,可以在什么位置赋值:直接赋值、静态初始化块
package day20.com.cn.homework; class Student { int age = 10; } class FinalTest { public static void main(String[] args) { int x = 10; x = 100; System.out.println(x); final int y=100; // y = 100; System.out.println(y); System.out.println("--------------"); //局部变量是引用数据类型 Student s = new Student(); System.out.println(s.age); s.age = 100; System.out.println(s.age); System.out.println("--------------"); final Student ss = new Student(); System.out.println(ss.age); ss.age = 100; System.out.println(ss.age); // ss = new Student(); } }
十、抽象类
- 抽象类特点 :抽象类不能实例化
- 只要有抽象方法的类,此类肯定是抽象类
- 抽象方法:没有方法体的方法,称为抽象方法
- 抽象类不一定有抽象方法
- 抽象类也有自身的成员变量、构造器、行为方法
- 只要子类继承于抽象类,此子类必须重写抽象类的抽象方法
- 父类是抽象类,子类也是用抽象类,那么子子类
abstract class A{ public abstract void info(); //抽象方法 } public class MainTest{ public static void main(String[]args){ //抽象类不能实例化 //A a=new A(); } }
abstract class A { private int a = 100; public A() { } //抽象方法 abstract void info(); } abstract class B extends A { /*
public void info()
{
System.out.println("B info"); //这个方法就不需要重写
}*/ abstract void info2(); } class C extends B { public void info() { } public void info2() { } } public class MainTest { public static void main(String[] args) { //抽象类不能实例化 //A a=new A(); //B b=new B(); C c = new C(); } }
十一、模板设计模式
-
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模
板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象
类的行为方式。
abstract class Template { //定义一个方法,此方法实现模板功能 //1、记录调用方法之前的当前时间点 //2、执行方法 //3、记录调用方法之后的当前时间点 //4、执行方法之后的当前时间点-记录调用方法之前的当前时间 点 public final void getTime() { //记录调用方法之前的当前时间点 long start = System.currentTimeMillis(); doMethod(); //记录调用方法之后的当前时间点 long end = System.currentTimeMillis(); //执行方法之后的当前时间点-记录调用方法之前的当前时 间点
System.out.println("执行时间是:" + (end - start)); } public abstract void doMethod(); } class A extends Template { public void doMethod() { for (int i = 0; i < 20; i++) { System.out.println("a do method i=" + i); try { //耗时1秒钟 Thread.sleep(1000); } catch (Exception e) { } } } } class B extends Template { public void doMethod() { for (int i = 0; i < 5; i++) { System.out.println("a do method i=" + i); try { //耗时1秒钟 Thread.sleep(1000); } catch (Exception e) { } } } } public class MainTest { public static void main(String[] args) { /*
A a=new A();
a.getTime();
*/ B b = new B(); b.getTime(); } }
十二、接口
-
从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方
法的定义(抽象方法),而没有变量和方法的实现。
修饰符 interface 接口名{ //常量![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080909522422.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzYwMDg4Mw==,size_16,color_FFFFFF,t_70) //抽象方法 }
-
修饰符
针对访问权限:
public/default(缺省) -
常量
如果在接口定义一个变量,此变量其实常量(final static 省
略) - 抽象方法的默认访问权限:public
- 如何定义
/*
定义一个接口
*/ interface Runner { //抽象方法,默认的访问权限:public void start(); void run(); void stop(); //final static int a=100; int a = 100; } class Person implements Runner { //重写: //规则: //两同、一小、一大 public void start() { System.out.println("perosn start"); } public void run() { System.out.println("perosn run"); } public void stop() { System.out.println("perosn stop"); } } public class MainTest { public static void main(String[] args) { Runner.a = 200; } }
1、接口的特点
- 接口也是不能实例化
- 接口可以多实现
- 实现类实现此接口,此实现类需要重写接口的抽象方法
- 接口支持多态
- 当使用default修饰时,不用必需实现该抽象方法,且用这个修饰时,只是一个方法体了
/*
定义一个接口
*/ interface Runner { //抽象方法,默认的访问权限:public void start(); void run(); void stop(); //final static int a=100; int a = 100; } interface IFly { void fly(); } class Person implements Runner, IFly { //重写: //规则: //两同、一小、一大 public void start() { System.out.println("perosn start"); } public void run() { System.out.println("perosn run"); } public void stop() { System.out.println("perosn stop"); } public void fly() { System.out.println("perosn fly"); } } public class MainTest { public static void main(String[] args) { //new Runner(); IFly f = new Person(); f.fly(); ((Person) f).run(); } }
本文地址:https://blog.csdn.net/weixin_43600883/article/details/107889596
上一篇: ES6——对象
下一篇: 07:面向对象【4】