类与对象(oop)
java是面向对象的编程(oop)语言
面向对象三大特征:
- 封装 (Encapsulation)
- 继承 (Inheritance)
- 多态 (Polymorphism)
类
就是模板,一些具有相似属性的对象的特征抽取归为为一个大类,例如人,学生,狗,汽车等都是类,都可以定义为类
修饰符 class 类名 {
//定义属性部分
修饰符 属性1的类型 属性1;
修饰符 属性2的类型 属性2;
…
//定义方法部分
方法1;
方法2;
…
方法m;
}
//(类名首字母大写,大驼峰命名)
对象
类的具体实例化,比如 狗这个大类中的对象是一条哈士奇;
一个类可以有多个对象,
Student student1 = new Student();
Student student2 = new Student();
修饰符
public、protected、default、private
一般在开发中 成员变量都用 private 修饰 ; 开发规范
当 修饰符修饰类时 ,在⼀个.java的⽂件中,只能有⼀个public class的声明,有多个public则编译报错,其类名 称必须与⽂件名称完全⼀致,但是允许有多个class的声明*
public class A{ //A == > A.java 文件 ==> 编译 A.class
public static void main(String [] args){
System.out.println(“A”);
}
};
class B{};
class C{};
只有public修饰的类,才能在包外部包可⻅;否则只是包内私有的类,类不能被其他包访
问 ; 所以我们一般声明类为 public
访问权限:
修饰符 | 当前类 | 同⼀包内 | 不同包中的⼦类 | 不同包中的⾮⼦类 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
default | Y | Y | N | N |
private | Y | N | N | N |
方法
定义
修饰符 返回类型 ⽅法名(参数类型 参数名,参数类型 参数名...){
//⽅法体
return
}
return 可以代替break;
return; return 后面什么都不写, 表示方法结束
- ⽅法⼊参
- 基础数据类型
- 引⽤数据类型
- ⽅法返回类型
- return xxx 具体类型
- 如果不⽤返回,则⽅法返回类型上写 void
方法调用
第一种情况: 在main方法内调用, 在其他类方法调用
步骤:
- 创建调用方法所在类的对象
- 使用对象.方法名()调用
第二种情况: 在本类的(除main方法)其他方法调用
直接调用: 方法名()
**注意 :在同一个类中, 静态方法只能调用静态成员变量和静态方法 , 普通方法既可以调用静态方法和成员变量 也可以调用普通的成员变量和方法 , **
static
- static关键字
- static修饰的⽅法或变量,优先于对象执⾏,所以内存有会现有 static修饰的内容,后有对象的内容
- 可以⽤来修饰类的成员⽅法、类的成员变量,还可以编写static静态代码块
- 修饰变量就是类变量,修饰⽅法就是类⽅法
- 总结: 类变量或者类⽅法,可以直接通过类名.⽅法名或者变量名进⾏调⽤,不⽤经过对象
static变量也称作静态变量
和⾮静态变量的区别是,静态变量被所有的对象所共享,在内存中只有⼀份,它当且仅当在
类初次加载时会被初始化。⾮静态变量是对象所拥有的,在创建对象的时候被初始化,存在
多个副本,各个对象拥有的副本互不影响
static成员变量的初始化顺序按照定义的顺序进⾏初始化
static⽅法也称作静态⽅法
不依赖于任何对象就可以进⾏访问,类名.⽅法名
不能访问类的⾮静态成员变量和⾮静态成员⽅法
注意事项:
静态⽅法不能直接访问⾮静态变量
静态⽅法当中不能使⽤this
核⼼:⼀个类⾥⾯ static修饰的不能访问⾮static修饰的成员或者⽅法,⽽⾮static修饰的可以
访问static修饰的成员或者⽅法
static也可 通过对象来调用 , 对象名 . 的方式
class student{
String name;
static int age;
public static int getAge(){
return age;
}
public int getName(){
name = "张飞";
return age;
}
}
静态代码块
加载类的时候,静态代码块会被执⾏⼀次,且只能执⾏⼀次
静态内容优先于⾮静态内容,所以静态代码⽐构造⽅法先执⾏
使⽤场景:⽤来⼀次性对静态成员变量进⾏赋值,或者类资源初始化等操作
代码块
{
//代码
}
代码块会在 static代码块后 构造方法之前 执行 , 每构造一个对象 ,就执行一次
public class 类名{
static {
//静态代码块
}
}
final
- final 修饰的类不可被继承
- final 修饰的方法不可被重写
- final 修饰的变量 为常量 ,不可被修改
- 一般常量定义为 public static final String STUDENT_NAME = “Tom”;
- String 被final修饰 , 不能被继承
this关键字
-
this
- 当⼀个对象创建后,JVM会给这个对象分配⼀个引⽤⾃身的指针,这个指针的名字就是 this
- 只能⽤于⾮静态⽅法体内,静态⽅法和代码块不能出现this (静态资源属于对象所共享的,而不属于某一个对象,所以就不能有引用指向)
- this就是指向当前对象本身
-
使用
-
set , get 方法中
构造函数中
/** * 构造函数可相互调用,用this关键字; * 且必须放在第一行; */ public User(){ this("jack",12); //有参构造 // this.age=18; System.out.println("无参数构造函数调用"); } public User(String name,int age){ // this(); //无参构造 this.age=age; this.name=name; }
-
OOP构造函数
构造函数
⼀种特殊的⽅法 ,创建对象时⽤来初始化对象(主)和赋初值(次),每次使⽤new 创建对象的时候,就会使⽤构造函数
与类具有相同的名称,可带参数,但是没有返回值
Java会⾃动为每个类提供⼀个默认构造函数
如果⾃⼰定义了构造函数,就不再使⽤默认构造函数,如果没有显示的写出默认构造函数,则会消失,如果有显示的写出默认构造函数, 则默认构造函数会存在
注意点:如果构造函数之间互相调⽤,务必写在⽅法第⼀⾏
//默认构造函数
public 类名(){
}
//⽆参构造函数
public 类名(){
//写⾃定义的语句
}
//有参构造函数
public 类名(参数类型1 参数名1,参数类型2 参数名2...){
//⾃定义⽅法体
}
构造函数的修饰符
public ⽤的最多,⽤来创建对象
private 私有化构造函数,不给外部创建对象,⽐如⼯具类,或者单例设计模式
default 默认的话,只能在当前包⾥⾯使⽤new 创建对象,⼏乎不⽤
OOP 封装
封装
- 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接⼝即⽅法
- 在java中通过关键字private,protected和public实现封装。
- 什么是封装?
封装把对象的所有组成部分组合在⼀起,封装定义程序如何引⽤对象的数据,
封装实际上使⽤⽅法将类的数据隐藏起来,控制⽤户对类的修改和访问数据的程度。 适当
的 封装可以让代码更容易理解和维护,也加强了代码的安全性 和复用
- 类封装
- ⽅法封装
OOP继承
-
继承
- ⼦类继承⽗类的特征和⾏为,使得⼦类对象具有⽗类的⽅法和属性
- java中的继承,减少重复代码
-
定义
-
class ⽗类名称{ } class ⼦类名称 extends ⽗类名称{ }
-
-
特点
- ⼦类拥有⽗类的⾮private的属性和⽅法
- ⼦类可以⽤⾃⼰的⽅式实现⽗类的⽅法 override(重写,覆盖)
- 实现了代码的复⽤
- 重写从⽗类那⾥继承来的⽅法的,当调⽤⽅法时候会优先调⽤⼦类的⽅法(默认就近原则 , 当子类与父类有同名的方法时,优先调用子类的方法 ,要想调用父类的,用super关键字)
- super
- ⼀个引⽤变量,⽤于引⽤⽗类对象
- ⽗类和⼦类都具有相同的命名⽅法和属性时,要调⽤⽗类⽅法时使⽤
- super也是⽗类的构造函数,格式 super(参数)
public Cat(){ super();//父类构造函数,默认存在,写不写都可,如果是有参构造就得写上 //所以初始化时先调用父类构造函数,再调用子类构造函数 //每个⼦类构造⽅法的第⼀条语句,都是隐含地调⽤super(),如果⽗类没有这种形式的构造函数,那么在编译的时候就会报错 //必须第一行 ,与this()一样,所以只能出现一个 //this()和super()都指的是对象,均不可以在static环境中使⽤ System.out.println("子类构造函数调用"); /** * 当父类是有参构造时,必须写父类构造 */ }
-
!!!重点
- java不⽀持多继承,⽀持多重继承,多重继承提⾼了耦合性,组合优于继承
- 所有的类都是继承于 java.lang.Object
- fifinal关键字
- 修饰的类,则这个类不可以被继承
- 修饰⽅法,则这个⽅法不允许被覆盖(重写)
java继承后类的初始化顺序
从左向右
静态代码块、⾮静态代码、⽗类/⼦类⽆参构造⽅法、⽗类/⼦类的⼀般⽅法
-
子类对象实例过程
- 初始化父类的属性
- 执行父类的构造方法
- 初始化子类的属性
- 执行子类的构造方法
OOP多态(抽象)
抽象概念
对类的一些相同特征的不同表现形式做进一步抽象成一个类, 而这个类我们称之为抽象类,
比如动物都有年龄和名称,但是吃的不⼀样,⽺吃草,⽼⻁吃⾁,但是都是闭着眼睛睡觉的
抽象类将事物的共性的东⻄提取出来,由⼦类继承去实现,代码易扩展、易维护
当⽗类的某些⽅法不确定时,可以⽤abstract关键字来修饰该⽅法,即抽象⽅法,⽤abstract
来修饰该类,即抽象类
//抽象类
public abstract class 类名{
//抽象⽅法,不能有⽅法主体
public abstract 返回类型 ⽅法名();
}
抽象特点
- 抽象类
- 抽象类不能被实例化,因为抽象类中⽅法未具体化,这是⼀种不完整的类,所以不能直接实例化,编译⽆法通过
- 抽象类中不⼀定包含抽象⽅法,但是有抽象⽅法的类必定是抽象类
- 如果⼀个抽象类中可以没有抽象⽅法,这样做的⽬的是为了此类不能被实例化。
- 抽象类的⼦类必须给出抽象类中的抽象⽅法的具体实现,否则⼦类也是抽象类,需要⽤ abstract声明
- 抽象类不能使⽤fifinal关键字修饰,因为fifinal修饰的类是⽆法被继承
- 抽象⽅法的特点
- 抽象类中的抽象⽅法只是声明,不包含⽅法体
- 抽象⽅法不能⽤private修饰,因为抽象⽅法必须被⼦类实现(覆写),⽽private权限 对于⼦类来 说是不能访问的
- ⼀个类继承了⼀个抽象类,那么它必须全部覆写抽象类中的抽象⽅法,当然也可以不全部覆写,如果 不覆写全部抽象⽅法则这个⼦类也必须是抽象类
!!! 构造⽅法,类⽅法(即static 修饰的⽅法)不能声明为抽象⽅法
Interface 接口
-
接口含义
- 是抽象⽅法的集合,接⼝通常以interface来声明,⼀个类通过继承接⼝的⽅式,从⽽来继承 接⼝的抽象⽅法
//接口可以继承接口 ,可多继承, 用extends关键字; interface 名称 [extends 其他的接⼝名···] { // 声明变量 // 抽象⽅法 int getMoney(); }
-
接口特点
- 接⼝的⽅法都是抽象⽅法,默认都是 public abstract,其他修饰符都会报错
- 接⼝中可以含有变量,但是接⼝中的变量会被隐式的指定为 public static final
- 接⼝⽆法被实例化,需要被实现才⾏
- ⼀个实现接⼝的类,必须实现接⼝内所描述的所有⽅法,否则就必须声明为抽象类
- 接口不同于类 ,有如下区别
- 接⼝没有构造函数
- 接⼝⾥可以有静态⽅法和⽅法体
- 接⼝不是被类继承了,⽽是要被类实现
- 接⼝⽀持多继承, 类不⽀持多个类继承
- 接⼝中所有的⽅法必须是抽象⽅法(JDK8之后就不是)
-
实现接口 implements
class 类名 implements 接⼝名称[, 其他接⼝名称, 其他接⼝名称]{ //要实现的⽅法 }
-
JDk8 接口新特性
- interface中可以有static⽅法,但必须有⽅法实现体,该⽅法只属于该接⼝,接⼝名直接调⽤ 该⽅法
- 接⼝中新增default关键字修饰的⽅法,default⽅法只能定义在接⼝中,可以在⼦类或⼦接⼝ 中被重写
default定义的⽅法必须有⽅法体
instanceof
-
判断⼀个类是否实现了某个接⼝,或者判断⼀个实例对象是否属于⼀个类
/* boolean result = object instanceof class class 类或者接口 object 对象 */ Student student=new Student(); boolean b= student instanceof Person; System.out.println(b); //true Person p1=new Student(); Person p2=new Teacher();//Teacher类 也继承了 Person类 // 对象类型强制转换前的判断 if(p1 instanceof Student){ Student s1=(Student) p1; }
⽅法重写 overriede
- fifinal 和 static的⽅法不能被重写
- 构造⽅法不能被重写
- 访问权限不能⽐⽗类中被重写的⽅法的访问权限更低
- 返回值和形参都不能改变
类型装换
-
自动类型转换:子类可以自动的转换成父类,可以轻松调用父类的方法
-
强制类型转换:父类不能自动转换成子类,需要强制类型转换
//自动类型转换 public static void main(String [] args){ Dog dog = new Dog(); Animal animal = dog; // 可以合并为一行代码 // Animal animal = new Dog(); } //强制类型转换 public static void main(String [] args){ Animal animal = new Dog(); //自动类型转换 Dog dog = (Dog) animal; } //!!! 以下这种转换不了 /* 类似于单独创建了一个Animal 类 ,而Dog类没有创建 , 因为Animal类中没有子类的构造 ; 上面的自动转换可以转换是因为 Dog类在new时会调用super()对父类进行构造,会自动返回父 类构造引用给等号左边; 同理 强制类型转换 第一步实际上就是一个自动类型转换,new Dog() 在创建时本身就会有 一个引用,将Dog对象退回到初始创建时的引用 ; */ public static void main(String [] args){ Animal animal = new Animal(); Dog dog = (Dog) animal; }