面向对象的特征
三大基本特征:
封装 继承 多态
特征:四个
封装 继承 多态 抽象
封装
对外隐藏事物的实现细节,只提供接口供外界访问
封装的好处
1.提高程序的安全性。
2.提高代码的复用性。
封装的体现
类:封装体
方法:
最大的体现:
私有的属性 公有的方法。
1.private:
私有的属性 表示通过private进行修饰的属性。
2.公有的方法:
格式:
① 设置 setter
public void set属性的名称(参数){
this.属性 = 参数的名称
}
注意:
set属性名称 ,该属性名称第一个字母必须大写,遵循小驼峰原则。
② 获取 getter
public 返回值类型 get属性的名称(){
return 属性;
}
代码
package com.demo;
/**
1.封装概述
2.private :权限修饰符,私有的,只有本类能使用。
*/
public class 封装概述 {
public static void main(String[] args) {
Student st = new Student();
//st.age = -100;
st.setAge(-100);
System.out.println(st.getAge());
}
}
class Student{
//私有的属性
private int age;
//公有的方法 设置属性
public void setAge(int age){
if(age >=0 && age <=120){
this.age = age; }
else {
System.out.println("年龄不合法");
}
}
//公有的方法 获取属性
public int getAge(){
return age;
}
}
setter与getter方法快捷键
格式:
① 设置 setter
public void set属性的名称(参数){
this.属性 = 参数的名称
}
注意:
set属性名称 ,该属性名称第一个字母必须大写,遵循小驼峰原则。
② 获取 getter
public 返回值类型 get属性的名称(){
return 属性;
}
快捷键:
alt + insert
继承
子类拥有父类的属性和方法,具有父类的特征
继承的实现
① 关键字 extends
class 子类 extends 父类
父类: superclass 超类
子类: subclass
一般可以写继承关系的 要求本质上是同一类事物
继承的好处
① 提高代码的复用性。
② 提高代码的扩展性
继承的特点(***)
① 单继承:extends关键字后只能有一个父类,继承的直系父类只有一个。
② 多重继承
继承的细节问题
对于父类与子类属性同名时,由于就近原则,如果是子类对象调用该属性,则使用的子类的属性。想使用父类的同名属性,
关键字:
super:指代当前对象的父类部分。
用法同this:
格式:
super. 属性名称
注意:
无论是this还是super 不能直接在静态方法中使用。
代码
package com.demo;
/**
1.学生对象、工人对象 老师对象
*/
public class 继承 {
public static void main(String[] args) {
Student st = new Student();
/*st.study();
st.sleep();*/
/* LittleStudent lt = new LittleStudent(); lt.study();*/
System.out.println(st.name);
st.show();
}
}
class Person{
String name ="张三";
int age;
public void sleep(){
System.out.println("睡觉");
}
}
//单继承
class Student extends Person{
String name = "李思";
public void study(){
System.out.println("goodgoodstudy");
}
public void show(){
System.out.println(super.name);
}
}
//
多重继承
class LittleStudent extends Student {
}
class Worker{
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
public void working(){
System.out.println("打工。。。");
}
}
class Teacher{
String name;
int age;
public void sleep(){
System.out.println("睡觉");
}
public void teaching(){
System.out.println("教java。。。。。。。。。。。。");
}
}
继承的成员
1.继承的成员可以都继承,除了以下两种:
① 成员用private修饰。
② 构造方法不能被继承。
方法的重写
1.方法的重载: overload 在同一个类中,方法名称相同,参数列表不同(个数,顺序,类型),与返回值无关。
2.方法的重写的原因:
父类的方法不适合子类的使用。
3.方法的重写: override
在具有继承关系的子类中,如果父类的方法不满足子类的需求,子类需要重写父类方法,重写时,
1》方法名称相同
2》参数列表相同
3》目前,返回值类型也相同(多态之前可以这样认为),
4》权限修饰符大于等于父类。
4.如果子类中要想调用父类的同名方法,需要通过super来调用:
格式:
super.方法名称(参数)
4.方法重写的校验:
① 可以通过上图进行校验。
② 注解@Override检测
代码
package com.exec;
/**
1.描述手机的来电显示功能
phoneI : 来电显示: 电话号码。
phoneII: 来电显示: 地区 大头贴 铃声 电话号码。
*/
public class Topic1 {
public static void main(String[] args) {
PhoneII pii = new PhoneII();
pii.display();
}
}
class PhoneI{
public void display(){
System.out.println("电话号码");
}
}
class PhoneII extends PhoneI{
public void display(){
//调用父类的同名方法 super.display();
System.out.println("铃声");
System.out.println("大头贴");
}
}
方法的重写注意:
① 重写要求必须是子父类之间,在子类中重写。
② 静态方法是不能被重写的。
③ 可以重写的方法都是非静态方法。通过对象调用,主要是为多态做准备。
this与super的用法
① this/super 指代对象
this 表示当前类的当前对象
super 表示当前类的当前对象的属于父类部分的引用。
注意:
this与super可以想象在子类对象中,一旦具有继承关系,就相当于子类对象创建时,由两部分组成,一部分属于继承父类super,另外一部分属于子类特有,称为this。
当查找时,this从本类开始进行查找。遇到第一个为止。super从父类开始查找,遇到第一个为止。
② this与super指代构造方法。
this指代本类的构造方法
super指代父类的构造方法。
格式:
this/super(参数)
注意:
1.默认如果一个子类的构造方法中没有显式的调用父类的构造方法,默认会有一个super() 默认的父类的无参空构造被调用。这种现象被称为隐式三步第一步.
2.如果父类构造中在有显式声明构造方法后,这些声明的构造方法中没有无参构造方法,此时,建议添加无参构造。
原因:
子类在进行构造方法的声明时,会在第一行默认调用父类无参构造方法。super(),如果类没有,就报错。
解决:
① 建议添加无参构造
② 也可以在构造方法第一行指定调用的是父类哪个构造方法。(不建议)
总结:
this与super的用法:
① 指代对象:
格式:
this/super.方法(参数)/属性
② 指代构造方法
格式:
this/super(参数)
代码
package com.demo;
/**
注意:1.默认如果一个子类的构造方法中没有显式的调用父类的构造方法,默认会 有一个super()
默认的父类的无参空构造被调用。这种现象被称为隐式三步第一步.
2.如果父类构造中在有显式声明构造方法后,这些声明的构造方法中没有无参构造方法,此时, 建议添加无参构造。
原因:子类在进行构造方法的声明时,会在第一行默认调用父类无参构造方法。super(),如果父 类没有,就报错。 解决:① 建议添加无参构造
② 也可以在构造方法第一行指定调用的是父类哪个构造方法。(不建议)
总结:this与super的用法:
① 指代对象: 格式: this/super.方法(参数)/属性
② 指代构造方法 格式:this/super(参数)
*/
public class Super指代构造方法 {
public static void main(String[] args) {
ZiK zk = new ZiK();
}
}
class ZK{ public ZK(String s){
System.out.println("这是ZK类的无参构造方法。。。1");
}
}
class ZiK extends ZK{
public ZiK(){
// 隐式三步:第一步 super()
super("abc");
System.out.println("这是ZiK的无参构造方法。。。2");
}
}
多态
概念
多态是同一个行为具有多个不同表现形式或形态的能力
多态的好处
提高了代码的扩展性
提高了代码的复用性
多态的分类
多态的类型:
向上转型:
父类引用指向子类对象。
向下转型:
解决多态向上转型的弊端。
多态向上转型弊端:
一旦发生了向上转型之后,由于对外是父类数据类型,不能调用子类特有的属性和方法。
代码
package com.demo;
/**
1.多态:
2.小女孩养宠物:
猫
哈士奇
老虎
*/
public class 多态 {
public static void main(String[] args) {
LittleGirl lg = new LittleGirl();
Cat c = new Cat();
lg.feed(c);// Animal c = new Cat() 多态的向上转型
Dog d = new Dog();
lg.feed(d);
Tiger t = new Tiger();
lg.feed(t);
Bird b = new Bird();
lg.feed(b);
Animal c1 = new Cat();
//一旦发生了向上转型之后,由于对外是父类数据类型,不能调用子类特有的属性和方法。
//c1.catchMouse();
}
}
class LittleGirl {
/*
public void feed(Cat c){
c.eat();
}
public void feed(Dog c){
c.eat();
}
public void feed(Tiger c){
c.eat();
}
*/
public void feed(Animal c){
c.eat();
}
}
class Animal{
public void eat(){}
}
class Cat extends Animal {
public void eat(){
System.out.println("猫吃鱼");
}
public void catchMouse(){}
}
class Dog extends Animal{
public void eat(){
System.out.println("哈士奇吃猫");
}
}
class Tiger extends Animal{
public void eat(){
System.out.println("老虎吃哈士奇");
}
}
class Bird extends Animal{
@Override
public void eat() {
System.out.println("鸟吃虫");
}
}
类与类之间的关系
分类
① 继承关系:本质是同一类事物 。 动物 –》猫
② 聚合关系: 整体和部分,可以分开。
③ 组合关系: 整体和部分,不可分割。
向上转型/里氏代换
概念
任何基类可以出现的地方,子类一定可以出现
多态的向下转型
原因
解决多态向上转型的弊端。
细节
1.多态向下转型:
格式:
强制类型转换
(要转换的类型)要转换的变量
2.向下转型弊端:
如果真实对象不是要转换的数据类型的对象,会报ClassCastException类型转换异常。
3.解决向下转型的弊端:
关键字:
instanceof
格式:
要转换的变量 instanceof 要转换成的数据类型
返回值为布尔类型。如果是对应的数据类型 ,返回true 否则 返回false。
注意:
instanceof后面的数据类型必须写精确,要转换成哪个类型就是哪个类型。不能使用父类。
代码:
package com.demo;
/**
1.多态向下转型:
格式:强制类型转换
(要转换的类型)要转换的变量
2.向下转型弊端:
如果真实对象不是要转换的数据类型的对象,会报ClassCastException类型转换异常。
3.解决向下转型的弊端:
关键字:
instanceof
格式:要转换的变量 instanceof 要转换成的数据类型
返回值为布尔类型。如果是对应的数据类型 ,返回true 否则 返回false。
注意:
instanceof后面的数据类型必须写精确,要转换成哪个类型就是哪个类型。不能使用父 类。
*/
public class 多态向下转型 {
public static void main(String[] args) {
Animal a = new Dog();
//向下转型 强制类型转换
/* if (a instanceof Cat) {
Cat c = (Cat) a;
c.catchMouse();
}
*/
System.out.println(a instanceof Animal);
}
}
class Animal {
public void eat(){}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void keepDoor(){
System.out.println("看门");
}
}
多态成员之间的调用问题
方法绑定
绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来
方法绑定的分类
1.静态绑定/前期绑定/编译期绑定:在编译时 就能确定执行哪个类的哪个方法。
2.动态绑定/后期绑定/运行期绑定: 在运行时,才能确定执行哪个类的哪个方法。
成员
1.编译期绑定: 属性(静态 或 非静态 ) 、静态方法、
2.运行期绑定: 非静态方法。
总结
编译看左 : 属性 和静态方法
运行先看左后看右: 非静态
先看赋值符号左侧的数据类型,确定要执行的方法,运行时,看右侧真实对象,决定是调用父类还是子类的重写方法。
编译看左 : 属性 和静态方法
运行先看左后看右: 非静态
先看赋值符号左侧的数据类型,确定要执行的方法,运行时,看右侧真实对象,决定是调用父类还是子类的重写方法。
代码:
package com.demo;
/**
1.编译期绑定: 属性(静态 或 非静态 ) 、静态方法、
2.运行期绑定: 非静态方法。
*/
public class 多态成员之间的调用问题 {
public static void main(String[] args) {
F f = new F();
ZiF z = new ZiF();
//向上转型
/**
10:20
30:40
10:20
*/
F zif = new ZiF();
/*
System.out.println(f.a + ":" + f.b);
System.out.println(z.a + ":" + z.b);
System.out.println(zif.a + ":" + zif.b);
*/
/*f.sfun();
z.sfun();
zif.sfun();
*/
f.show();
z.show();
zif.show();
}
}
class F{
int a = 10;
static int b = 20;
public void show (){
System.out.println("这是父类的非静态方法。。。。。1");
}
public static void sfun(){
System.out.println("这是父类的静态方法。。。。。。。。2");
}
}
class ZiF extends F{
int a = 30;
static int b = 40;
public void show (){
System.out.println("这是子类的非静态方法。。。。。3");
}
public static void sfun(){
System.out.println("这是子类的静态方法。。。。。。。。4");
}
}
代码块
概述
1.代码块:{}
2.常见代码块:
static {} 静态代码块 类中 方法外
{} 构造代码块 类中 方法外
{} 局部代码块 方法中
3.特性:
静态代码块: 随着类的加载而加载,并且只加载一次。多个之间 按照代码执行顺序,顺序加载,适用场景:类存在就需要使用的代码。
构造代码块:随着构造方法的执行而执行,并且每执行一次构造方法,都会执行一次代码块。并且在构造方法中的代码执行之前执行。多个也是按照代码执行顺序顺序执行。适用场景:当多个构造方法中有共性代码时,可以提取到构造代码块中执行。
局部代码块:位于方法中,主要是用来限定变量的作用域。
代码:
package com.demo;
/**
1.代码块: {}
2.常见代码块:
static {} 静态代码块 类中 方法外
{} 构造代码块 类中 方法外
{} 局部代码块 方法中
3.特性:
静态代码块: 随着类的加载而加载,并且只加载一次。多个之间 按照代码执行顺序,顺序加 载,适用场景:类存在就需要使用的代码。
构造代码块:随着构造方法的执行而执行,并且每执行一次构造方法,都会执行一次代码块。 并且在构造方法中的代码执行之前执行。 多个也是按照代码执行顺序顺序执行。适用场景:当多个构造方法中有共性代码 时,可以提取到构造代码块中执行。
局部代码块:位于方法中,主要是用来限定变量的作用域。
*/
public class 代码块 {
static int a;
//静态代码块
static{
a = 10;
System.out.println("这是静态代码块。。。。2");
}
//构造代码块
{
System.out.println("这是一个构造代码块...1");
}
{
System.out.println("这是一个构造代码块...5");
}
public static void main(String[] args) {
// System.out.println(a);
// new 代码块();
// new 代码块(5);
fun();
}
public static void fun(){
//局部代码块
{
int b = 5;
System.out.println(b+"========");
}
// System.out.println(b+"...");
}
public 代码块(){
System.out.println("这是无参构造方法。。。。3");
}
public 代码块(int a){
System.out.println("这是有参构造方法。。。。4");
}
}
对象的加载顺序问题
类的成员
属性
方法
构造方法
代码块
代码:
public class 对象的加载顺序 {
public static void main(String[] args) {
new F().fun();
}
}
class F{
static{
System.out.println("这是F类的静态代码块。。。。5");
}
{
System.out.println("这是F类的构造代码块。。。。6");
}
int a = setA();
private int setA() {
System.out.println("这是f类的显式初始化。。。4");
return 0;
}
public void fun(){
System.out.println("这是F类的非静态方法。。。1");
}
public F(){
System.out.println("这是F类的无参构造方法。。。。2");
}
public F(int a){
System.out.println("这是F类的有参构造方法。。。。3");
}
}
执行步骤
1.判断对象的加载顺序该类是否存在在方法区中,存在,直接使用,不存在,向硬盘上进行加载到方法区。
2.查找到main方法 压栈执行。
3.判断F类是否在方法区存在,存在,直接使用,不存在,向硬盘上进行加载到方法区。
4.由于有new关键字,在堆中开辟F类的对象空间,并且对属性a进行默认初始化。
5.根据构造方法,选择构造方法进行执行。
6.在执行构造方法中的代码之前,该位置需要执行隐式三步:
① super(参数)
② 构造代码块
③ 属性显式初始化
其中 ,②③根据程序的书写顺序,顺序执行。
7.隐式三步执行完毕之后,才会执行构造方法里面的代码。
8.如果有方法调用,此时再执行方法。没有不执行。
总结:
1》 先加载类:考虑继承 ,先父后子。 静态方法 静态属性 静态代码块,静态方法不调用 不执行。静态属性 静态代码块 顺序执行。
2》 对象:构造方法的执行:
① 隐式三步:super(参数) 考虑 继承 构造代码块 属性的显式初始化 顺序执行。
② 构造方法的代码的执行。
③ 有方法调用才会执行。
抽象类
抽象概念
不具体 共性的特征。
关键字:abstract
abstract 表示抽象
抽象方法
声明格式:
[权限修饰符]abstract 返回值类型 方法名称(参数列表);
抽象类
当一个类中拥有抽象方法时,该类也必须是抽象的。类的前面加关键字 abstract
抽象类声明格式:
[权限修饰符] abstract class 类名{ }
抽象类的特点
① 抽象类也是类,拥有的类的特点。可以有 属性 方法 构造方法
② 抽象类不能直接创建对象的。要创建对象,必须通过子类实现抽象类中的抽象方法,才能创建子类对象。
③ 一个类中如果有抽象方法,该类必须是一个抽象类,如果一个类是抽象类,未必有抽象方法。只要加关键字 abstract在类上就可以。
代码:
package com.demo;
public class 抽象类 {
public static void main(String[] args) {
Animal a = new Cat();
a.fun();
a.eat();
Animal a1 = new Dog();
a1.eat();
}
}
abstract class Animal{
public abstract void eat();
public void fun(){
System.out.println("这是一个fun方法。。。1");
}
int a = 5;
public Animal(){}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
抽象类与一般类的区别?
1.写法:
抽象类 abstract class
类 class
2.组成成员:
抽象类: 属性 方法 抽象方法 构造方法
类: 除了抽象方法。
3.创建对象:
抽象类: 不能创建对象
类: 可以直接创建对象。
4.对于方法的实现:
抽象类:如果有抽象方法,必须要重写。
类: 继承自父类的方法,可以重写也可以不重写。
模板设计模式
设计模式
是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
常见的设计模式
23种 。
模板设计模式:
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式
代码:
package com.demo;
/**
学生一天的生活:
① 吃 ② 睡 ③ 学习
*/
public class 模板设计模式 {
public static void main(String[] args) {
Student st = new LittleStudent();
/*st.eat();
st.sleep();
st.study();
*/
st.life();
Student mt = new MiddelStudent();
/*
mt.eat();
mt.sleep();
mt.study();
*/
mt.life();
}
}
abstract class Student{
public abstract void eat();
public abstract void sleep();
public abstract void study();
public void life(){
eat();
sleep();
study();
}
}
class LittleStudent extends Student{
@Override
public void eat() {
System.out.println("小学生吃零食");
}
@Override
public void sleep() {
System.out.println("小学生很晚睡。。。");
}
@Override
public void study() {
System.out.println("小学生天天玩耍");
}
}
class MiddelStudent extends Student{
@Override
public void eat() {
System.out.println("初中生边吃边学");
}
@Override
public void sleep() {
System.out.println("初中生边睡边读书");
}
@Override
public void study() {
System.out.println("初中生边学边睡。。");
}
}
构造方法与sette方法的区别
属性赋值
1.直接赋值:
对象.属性名 = 值
2.构造方法:
对于属性赋值,只能赋值一次,并且是在创建对象时 赋值一次。
3.setter方法
创建对象后,需要修改属性的值。
final用法
final
final用法:
① 修饰变量–》常量
② 修饰方法–》不能被重写
③ 修饰类 –》 不能被继承
代码:
package com.demo;
/**
1.final用法:
① 修饰变量--》常量
② 修饰方法--》不能被重写
③ 修饰类 --》 不能被继承
String
*/
public class Final用法 {
}
abstract class A{
public /*final*/ void fun(){}
//public abstract final void f1(); 注意 final 与abstract不能连用
}
class ZiA extends A{
@Override
public void fun() {
super.fun();
}
}
final finally finalize区别
1.final 用法
2.finally 异常 : 无论执行try还是执行catch最终都会执行 finally里面的内容。
3.finalize() 用于垃圾回收的方法。
接口
概念
接口: 协议 约定。
一系列的规范和约定,目前,接口中所有的方法都是抽象方法。(1.8之前 不包括)
接口的声明
格式:
关键字 interface
[权限修饰符] interface 接口的名称{
}
1.接口中的方法的声明:
接口中的方法都是抽象方法,一般会省略abstract不写。
2.接口中的属性的声明:
接口中的属性都是静态常量,一般会省略public static final不写。
接口的对象的创建
1.接口中的方法都是抽象方法,所以接口不能直接创建对象。
2.要想创建对象,必须要实现接口中的抽象方法。
3.要使用子类创建对象。
关键字:
implements
格式:
class 子类 implements 父接口1,父接口2{
}
代码:
package com.demo;
public class 接口的声明 {
public static void main(String[] args) {
T t = new ZiT();
t.fun();
}
}
//接口
interface T{
public void fun();//不写 也有abstract
int a =10;// 省略了 public static final 也是 静态常量
}
//子类
class ZiT implements T{
@Override
public void fun() {
System.out.println("这是接口中的子类。。。。");
}
}
接口的细节问题
1.接口的特点:
① 接口可以多实现:
② 接口可以多继承
③ 接口可以多重继承
2.接口与抽象类的区别与联系:
区别:
1》 写法:
抽象类: abstract class
接口: interface
2》 成员:
抽象类: 属性 方法 抽象方法 构造方法 代码块
接口: 抽象方法 静态常量 没有构造方法 代码块
3》 子类实现:
抽象类: extends
接口: implements
4》 特点:
抽象类: 继承 :单继承 多重继承
接口: 继承 : 多继承 多重继承 多实现
5》 用途:
抽象类: 同一种事物的共性的特征
接口: 不同事物之间的相同功能
联系:
把接口看成是特殊的抽象类,该类中所有的方法都是抽象方法的抽象类。
包
概述
包 :package
① 功能:分类管理java的文件。
② 包的命名规则:
原则:全球唯一。
公司域名的倒置 + 项目名称 + 模块名称 + 包的功能名称
如:cn.com.baidu.studentmanager.crud.add
③ 包的分隔符:
用点进行分隔,每一个点表示一层。
④ 包的声明:表明该类在哪个包下。如果没有package声明,在src下。
package 包的路径;
注意:
包的声明只有一个,并且在第一行。
⑤ 导包:指名该类在哪个包下。
import 类的路径
注意:
导包可以是多个,位于package下面。
代码:
package com.demo;
import java.util.Scanner;
public class 包 {
public static void main(String[] args) {
//类的完全限定名
// java.util.Scanner sc = new java.util.Scanner(System.in);
}
}