面向对象
一切事物都为对象
包括封装、继承、多态
类和对象
java通过类描述事物,类由属性、行为构成,类是一切具有相同属性和行为的统称
抽象是将所有的属性和行为提取出来的过程
对象是某一类事物的某个具体存在,通常也称为实例instance
事物的属性称为成员对象、成员变量
事物的行为称为成员方法
成员变量在声明时可以直接赋值,声明后不能在类中赋值,所以继承后的类中不能给父类中的成员变量在类内赋值
创建对象
即类的实例化
类名 对象名 = new 类名();
创建对象:new+构造器(),如果没有定义显式的构造器,则系统默认提供一个空参构造器
匿名对象:new 类名().方法/属性,即不设置变量名
构造器
构造器可以用来初始化对象,即在实例化对象时,在括号内添加相应的参数
class 类名{
权限 与类名相同的方法名(参数列表){
语句;
}
}
构造器可以有多个,即构造器支持重载,可以把构造器看作是返回值为void
的方法
class Animal{
String name;
private int weight, height;
public Animal(String name){
this.name = name;
}
public Animal(){
System.out.println("创建成功,没有提供构造器的参数");
}
public void setName(String name) {
this.name = name;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void setHeight(int height) {
this.height = height;
}
}
构造一个Animal类
Animal dog = new Animal("狗");
//此时相当于执行的第四行,为name成员变量赋值的方法
Animal dog = new Animal();
//此时相当于执行的第七行,直接输出 创建成功,没有提供构造器的参数
使用对象
使用成员对象 类名.变量名
使用成员方法 类名.方法名();
成员变量:定义在类中 方法外,默认值为null
成员方法:去掉static修饰符
类需要存储在一个新建文件中,如果调用类,则再次新建一个类,类里边包含main进行调用
可以使用对象名.变量名
直接对类内非私有变量直接赋值
#####创建类
package 面向对象;
public class phone {
//定义成员变量
int a, b;
//定义成员方法
public void fangfa1(int a, int b) {
System.out.println("a+b的值为" + (a + b));
}
}
#####调用类
package 面向对象;
public class Main {
public static void main(String[] args) {
//若要使用类,需要先创建对象
phone p=new phone();
//调用成员变量并赋值
p.a=1;
p.b=2;
//调用成员变量并打印
System.out.println(p.a);
System.out.println(p.b);
//调用成员方法
p.fangfa1(p.a,p.b);
}
}
成员变量与局部变量
成员变量定义在类内,成员方法外,成员变量有初始化值,默认为null ,作用范围是整个类内,随着对象的创建而存在,随着对象的消失而消失
局部变量定义成员方法中,或者是形式参数,无初始化值,作用在方法中,随着方法的调用而存在,随着调用结束而消失
若局部变量与成员变量名称冲突时,采用就近原则,类中的成员变量在声明时可以赋初值
如果直接使用对象名 = 另一个对象名,此时相当于把另一个对象的地址给了这个对象,改变其中一个的值,另一个的值也改变
public class hello {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Person people = new Person();
people.name= "admin";
System.out.println(people.name);
Person p2 = people;
p2.name = "Microsoft";
System.out.println(people.name);
}
}
public class Person {
String name;
int age;
boolean sex;
public void eat() {
System.out.println("人会吃饭");
}
}
//执行结果
//admin
//Microsoft
封装
将功能封装在一块,提供使用的功能,类的对象何以频繁被使用
四种权限(针对变量和方法的)
修饰 | 可用范围 |
---|---|
private | 类内 |
缺省,不说明权限 | 类内,同一包内 |
protected | 类内,同一包内,不同的包的子类 |
public | 类内,同一包内,不同的包的子类,同一个工程内 |
修饰类只能用public
或者缺省
好处
提高安全性
提高复用性
复杂事情简单化
####举例
类和方法都体现了封装
写个打印数组的函数并封装到类中,每次执行调用类来打印,也体现了封装
public 是公共的意思,可以在任意类中访问public权限的类
private关键字
私有意思,是一种访问权限修饰符,用来修饰类中的成员
特点是修饰的成员只能在本类中进行访问
语法
private 数据类型 变量名
private 返回值类型 方法名(参数列表)
{
语句;
}
public一般用来修饰成员变量
private一般用来修饰成员方法
this关键字
意为本类对象的引用,本质也是个对象,可以理解为当前对象
特点:每个普通的函数(方法)都有一个this,谁调用该方法,this就指向谁,方法也可以通过this进行调用,通常都省略,也可以用来修饰构造器
this是为了解决以下(第四行)问题(成员变量和局部变量重名):
public class stu{
private String name;
public void setname(String name){
name = name;//就近原则,此时两个name都为形参name
}
}
解决:
public class stu{
private String name;
public void setname(String name){
this.name=name;
}
}
也可以用来减少代码的冗余度
class Animal{
String name = "没有名字";
private int weight, height;
public Animal(){
System.out.println("无参构造");
}
public Animal(int weight, int height){
this.height = height;
this.weight = weight;
}
public Animal(String name){
this.name = name;
}
public Animal(String name,int height,int weight){
this.name = name;
this.height = height;
this.weight = weight;
}
}
以上代码中,构造器的冗余部分过多,可以中this
进行减少冗余度,此时的this相当于当前对象,即this(参数列表)
也相当于一个构造器,不能自己调用当前的构造器
class Animal{
String name = "没有名字";
private int weight, height;
public Animal(){
System.out.println("无参构造");
}
public Animal(int height, int weight){
this.height = height;
this.weight = weight;
}
public Animal(String name){
this.name = name;
}
public Animal(String name,int height,int weight){
this(height,weight);//相当于调用的是第7行的this
this.name = name;
}
}
用法:
this.属性名;
this.方法名(参数);
构造器
new关键字是用来构造方法的
构造方法是用来初始化对象的
默认的无参构造器的权限与类的权限一致
格式
修饰符 构造方法名(参数列表){
方法体
}
构造方法时,方法名必须与类名一致,没有返回值但可以写return,也没有返回值类型
注意事项:
- 若未构造方法,系统将自动进行无参构造
- 若已构造,系统不再构造
- 构造方法可以重载
例子
有参构造和无参构造区别
package 面向对象2;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner ito=new Scanner(System.in);
stu p=new stu();//属于无参构造
stu p2=new stu("admin",18);//有参构造
p2.print();//有参构造,已赋初值
System.out.println();
p.print();//无参构造,未赋任何初值
}
}
package 面向对象2;
public class stu {
public stu() { //无参构造
}
public stu(String name, int age) { //为stu的重载,属于有参构造
this.name = name;
this.age = age;
}
private String name;
private int age;
public void setNameAge(String name, int age) {
this.name = name;
this.age = age;
}
public void print() {
System.out.print("姓名:" + (name) + " 年龄:" + (age));
}
}
标准的JavaBean类
即Java语言写成的可重用组件
是指符合
- 类是公共的
- 有一个无参的公共构造器
- 有属性,对应get和set方法
public class 类{
//成员变量,全部使用private修饰
//沟构造函数/方法 分为有参构造和无参构造
//公共的访问方式
}
继承
extends
,中文为延长、扩展
概念
- 让类与类之间产生父子关系
- 被继承的称为父类(基类、超类、基类),superclass
- 继承的类称为子类(派生类),subclass
- 一个类只能有一个父类,不能有多个,所以Java的继承为单继承
- 允许多层继承
- 如果没有声明一个类的父类,那么该类默认继承自
java.lang.Object
类,因此每个类中默认有 - 父类中的构造器不会直接被继承
方法的重写
在子类中,可以对父类已有的方法进行改造,也成为该方法的重置、覆盖,程序执行时,子类的方法将覆盖父类的方法
- 方法名和形参列表必须要一样
- 子类中重写的方法的权限修饰符不小于父类的权限修饰符
- 子类中不能重写父类中
private
权限的方法 - 如果父类的返回值类型为基本数据类型,那么父类被重写的方法和子类中重写的方法的返回值要相同,如果父类的返回值类型是类,父类中返回值的类型时A类,子类中返回值的类型可以写为A类的子类
- 只有非static的方法可以重写
变量的重写
变量在子类中重写后,使用父类中原有的getter
或者setter
时,是对父类中的该变量进行赋值,而不是对子类中的重写后的变量进行赋值,属性(变量)在重写后不会覆盖父类中原有的属性,而是作为两个独立存在的属性放到内存中
super关键字
当子类重写父类的方法后,如果还想在子类中调用原来被重写前的方法/变量,可以使用super.
关键字调用重写后的父类中的属性/方法
子类中调用与父类中不重名的方法/属性时,直接写方法和属性即可此时等价于super.属性/方法名
与this.
相类似
super也可以去间接父类中寻找
例如c是b的子类,b是a的子类,a中有一个aa方法被c重写了,如果在c中找之前的aa方法,可以直接使用super
super添加形参列表代表调用父类的构造器,即可以使用super(形参列表)
调用父类的指定的构造器,在子类的构造器中,this构造器和super构造器只能出现一个,因为Java限制**'super()' 或者 'this' 的调用必须是构造方法的方法体中的第一条语句**,如果构造方法中没有写任何的语句,则默认是调用super()
的,即调用空参构造器,视频的7分08秒
如果父类中只有非空参的构造方法,那么子类中,如果子类中写一个新的构造方法时,会报错,因为此时子类中的构造器需要调用super()
,此时找不到空参构造方法,为保险起见,最好给每一个类保留一个空参的构造方法
public class test{
public static void main(String[] args){
peopleInfo people = new peopleInfo();
people.getId();
}
}
class info{
int id = 1001;
String name;
}
class peopleInfo{
int id = 1002;
public void getId(){
System.out.println("id = " + id + "superId = " + super.id);//第一个id等价于this.id
}
}
以上输出结果为id = 1001 superId = 1002
子类中使用父类的构造器
class Animal{
String name;
int height, weight;
public Animal() {
}
public Animal(String name, int height, int weight) {
this.name = name;
this.height = height;
this.weight = weight;
}
}
class Dog{
public Dog(String name, int height, int weight){
super(name, height, weight);
}
}
多态
对象的多态性:用一个父类声明不同的子类,即父类的引用指向子类的对象(子类的对象赋给父类的引用)
//例如Man和Woman是Person的一个子类,
Person people1 = new Man();
Person people2 = new Woman();
此时的体现了这个对象是多种形态
以上方式实例化对象后,只能调用父类中有的方法和属性(如果方法被重写,那就调用重写后的,多态性不适用于属性),不能调用该对象所特有的方法和属性,也就是说 编译时看左边的类型,运行时看右边
有了继承才有多态,还要有方法的重写
使用强制类型转换可以调用子类中特有的方法,又被称为向下转型,要想向下转型,需保证new的是等号左边的一个子类
class Test{
public static void main(String[] args){
Animal dog = new Dog();
//此时的dog对象不能调用shout方法
//向下转型
Dog dog2 = (Dog) dog;
//此时的dog2可以调用shout方法
}
}
class Animal{
String name;
public void eat(){
}
public void drink(){
}
}
class Dog extends Animal{
public shout(){
}
}
instanceof关键字
中文:实例,读音'ɪnstənsəv
作用:判断一个对象是否是一个类的实例,向下转型时可能会出现异常,为了避免该情况,可以使用instanceof
进行判断,不能判断基本数据类型
Animal dog = new Cat();
Dog dog2 = (Dog) dog;//编译会通过,但执行会出现异常,可以使用instanceof进行判断
//修改为
if(dog instanceof Dog){
Dog dog2 = (Dog) dog;
}
boolean类型
用法:实例变量(对象) instanceof 类名
##abstract关键字
只能用来修饰类和方法,不能修饰私有方法
###抽象类
在类前使用abstract
进行修饰,'æbstrækt
,抽象的、理论的
有的类不能够被初始化,例如这个类是作为其他多个类的基类时,这个类中仅保存着其他类的共有的属性,即使被初始化,也没有相关的意义,可以用abstract
进行修饰限定不可用于初始化一个对象,即不能被new
出来
###抽象方法
abstract
关键字也可用于方法前,格式为权限修饰符 abstract 返回值 方法名(参数列表);
仅能在抽象类中存在抽象方法,抽象方法不允许有方法体
当继承于含有抽象方法的抽象类时,必须重写覆盖父类中的抽象方法,抽象方法常常作为多态进行使用(因为只能调用父类中有的方法和属性(如果方法被重写,那就调用重写后的,多态性不适用于属性),不能调用该对象所特有的方法和属性),可以看作是函数声明
####格式
class 父类{
//语句
}
class 子extends 父类{
//语句
}
继承之后的效果
子类继承父类的非私有成员
Alt+insert
快速构造函数(方法)
如果子类中没有重写父类的abstract
方法,那么该类也是抽象类
匿名类
有这么一个抽象类
abstract class a{
int a;
abstract public void fun1();
}
也可以用来直接创建匿名类
a aaa = new a(){
public void fun1(){ //此时需要重写覆盖a类中的抽象方法
};
}
如果没有抽象方法,那么必须要随意的覆盖一个方法
Object类
- 是所有Java类的一个父类
- 有一个空参构造器
- 垃圾回收的方法在该类中定义,垃圾回收之前会调用该方法,即finalize
ˈfīnlˌīz
(敲定)方法
equals()方法
在Java中,==
可以判断基本数据类型是否相等,引用类型的地址是否相等,所以,需要```equals()``方法来判断里边的值是否都相等
equals()
方法需要自行重写,默认的equals
方法中仅能判断地址是否相同(即与==作用相同)
public boolean equals(Object obj) { //默认的equals方法
return (this == obj);
}
toString()方法
toString方法重写前默认返回对象的地址,toString()
为对象名的默认返回值,即System.out.println(对象名)
的内容,与python中的__str__
方法作用效果一致
package
中文含义为包,ˈpakij
实现对项目更好的管理,可以使用package声明类或者接口所属的包,声明在源文件首行
同一个包下,不能定义同名的接口或者类
import
导入,使用定义在不同包中的类
import 包名.类名;
导入一个包中所有的类
import 包名.*;
import目的是省下其他包的类名前的包名
假设有以下的包
├─test
│ Animal.java
│ test.java
│
└─test2
test2.java
test2下的test2类想要使用test下的Animal类创建对象,可以使用语句
test.Animal a = new test.Animal();
也可以使用import进行简化
import test.Animal;//先导入包
Animal b = new Animal();//直接引用
如果导入的类与本包内的类名冲突,则以导入的为准
如果使用多个不同的包,并且重名的类,那么只能写全称,即包名.类名
java.lang.*
包默认是导入的
静态import
:import static 类.静态变量/方法
,仅可导入类的静态方法和变量,使用时,无需再添加类名,不可以滥用,滥用会导致重名!!!
单元测试
用于代码测试使用
生成方式:idea ALT + insert 选择测试
- 测试的方法的权限必须是public,并且没有返回值,没有形参
- 添加注解
@test
并导包 - 运行此类
- 如果没有抛出异常,则显示通过测试
- 在生成的方法名前右键,可以只测试右键的方法
static关键字
中文是静态的
static可以修饰:属性、方法、代码块、内部类
使用static修饰的变量为静态变量,在一个类中,该变量是共享的
非静态变量又称为实例变量
class dog{
static int a;
}
public class test{
public static void main(){
dog test1 = new test();
test1.a = 999;
dog test2 = new test();
test2.a = 888;
}
}
此时的test1.a = test2.a = 888
- 静态变量随着类的加载而加载
- 实例变量随着对象的加载而加载
- 静态变量的加载早于对象的创建
- 静态变量存在与方法区中的静态域中,仅加载一次,当加载到方法区中后,无论进行何种操作,都不会离开方法区,除非内存不足或者关掉Java虚拟机
- 类可以调用直接静态变量、静态方法,不可以调用实例变量(非静态变量)、非静态方法
- 对象可以调用静态变量、静态方法、实例变量、非静态方法
- 在一个类中的静态变量前省略的是
类名.
,而并非this.
- 静态方法中,只能调用静态的方法和使用静态的变量,不允许使用非静态的方法/变量,也不能使用super、this关键字
- 非静态方法中,可以任意使用静态或者非静态的方法/变量
- 构造器不能使用static修饰
main方法的使用
- 是程序的入口
- 必须是静态的方法
- 一个文件中可以有多个main,运行时可以选择需要运行哪个
- args中有传递的参数
代码块
又被称为初始化块
结构
{
语句;
}
作用
-
用来初始化类和对象
-
可以添加其他修饰符,但只能用static修饰
static { 语句; }
-
代码块内部可以有输出语句
-
静态代码块
- 随着类的加载而执行
- 当一个类被首次创建时,会执行
- 当首次执行一个类中的静态方法或者使用静态变量时也会执行
- 随着类的加载而执行
-
非静态代码块
- 随着对象的每一次创建而执行,即每创建一次,执行一次
- 最大的作用是在对象的创建时对属性进行初始化
执行顺序默认初始化->显式初始化->代码块->构造器初始化->对对象中的方法、属性进行操作
final关键字
中文是最后,太监类
可以用来修饰类、对象、方法
-
修饰类
- 类前添加final修饰符时,该类无法再被其他类继承了
- String类、System类都是使用final修饰的
-
修饰方法
- 代表这个方法无法被重写了,即同返回值,同参数列表的无法被再次重写,但也可以被重载
- Object类中的getClass(获取当前对象所属的类)就是final修饰的,无法被重写
-
修饰变量
-
修饰后的变量就变成常量了
-
修饰属性
-
可以显式初始化,例如
final int a = 10;
-
可以在代码块中赋值
-
在构造器中赋值,当在一个构造器中赋值时,在其所有的构造器中必须都有赋值语句
例如
class a{ final int b; public a(){ b = 1; //相当于this.b } public a(int x){ //允许 b = x; //相当于this.b } }
-
-
-
-
修饰局部变量(局部变量包括:方法体内的变量、形式参数)
- 当为方法体内的变量时,只能使用显式初始化
- 当为形式参数时,仅调用函数可赋值,调用后无法在方法体内赋值
-
static final
常被称为全局常量
接口interface
中文:端口、接口、界面
Java不支持多继承,使用接口可以实现类似多继承的功能,接口和类是两个并列的结构
接口中不能定义构造器,也就是说,接口不能够被实例化,接口都是通过类来实现的
因为是通过类来实现的,而不是继承,所以使用关键字implements表示,一个类可以实现多个接口
implements中文为实现,ˈɪm.plə.ment
class 类名 implements 接口名1, 接口名2,....., 接口名n{
}
如果这个类实现了接口中的所有的抽象方法,那么这个类可以被实例化
如果这个类没有实现接口中的所有的抽象方法,那么这个类一定是抽象类
一个类可以同时继承一个类和实现多个接口
class 类名 extends 类名 implements 接口名1, 接口名2,....., 接口名n{
}
JDK 7以及之前只能定义全局常量和抽象方法
全局常量:public static final;修饰
抽象方法:public abstract;修饰
因为有这个限制,所以可以直接省略前边的修饰符,但声明后仍然是全局常量和抽象方法
JDK 8以及之后,除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
接口和接口之间可以多继承
接口也可以实现匿名类
接口名 变量 = new 接口名(){
重写接口中的抽象方法;
};
Java8以及以上的接口的特性
JDK 8以及之后,除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
全局常量:public static final;修饰
抽象方法:public abstract;修饰
静态方法:public static;修饰
默认方法:default;修饰//相当于public default,该方法无需再从实现类中重写,因为已经定义好了
- 实现类必须重写抽象方法
- 实现类可以不用重写默认方法
- 实现类可以调用默认方法
- 实现类及实例化后的对象不能调用接口中的
static
方法 static
方法只能使用接口名.静态方法名
调用- 如果子类(实现类)中继承的父类和实现的接口中(默认方法)有同名同参数的方法,并且没有在子类(实现类)中重写该方法,那么默认调用的是父类中的该方法
- 当实现类的多个接口有共同的同名同参数的默认方法,此时必须要在实现类中重写该方法
- 在实现类中也是可以调用接口中的默认方法,调用方式为
接口名.super.方法名()
内部类
Java允许将一个类放到一个类中,外层的类叫做外部类,内层的类叫做内部类
内部类分为成员内部类和局部内部类,局部内部类定义在方法内、代码块内、构造器内
//内部类
class AA{
public void fun(){
//局部内部类,方法内
class BB{
}
}
//局部内部类,代码块内
{
class CC{
}
}
//局部内部类,构造器内
public AA(){
class DD{
}
}
//成员内部类
class DD{
}
}
修饰
-
成员内部类可以用static修饰
-
当被修饰为静态时,无法调用外层类的非static方法
-
非静态内部类调用外部类时的方法/属性可以直接写,但此时相当于
外部类名.this.方法/属性
-
-
final修饰,代表无法被继承
-
abstract修饰,代表无法被继承
-
权限可以有4种,默认、public、private、protect
实例化
-
静态的内部类
- 在外部类外(其他类中)
外部类名.内部类名 变量名 = new 外部类名.内部类名()
- 在外部类中
内部类名 变量名 = new 内部类名()
- 在外部类外(其他类中)
-
非静态的内部类
-
在外部类外(其他类中)
-
先使用外部类new一个对象,并使用变量引用
-
外部类名.内部类名 变量名 = 之前new的对象的名字.new 内部类名()
-
class AA{ class BB{ } } class OtherClass{ AA a = new AA(); AA.BB = a.new BB(); }
-
-
Q.E.D.