java基础-OOP(封装、继承、多态)

OOP


对一类事物共有的特征的抽象描述

创建类
[权限修饰符] class 类名{
}

类的成员有:
1. 属性(成员变量)
2. 方法
3. 构造器
4. 代码块		
5. 内部类

创建对象
类名 标识符 = new 类名();

属性(成员变量)

成员变量:在类中,方法外
当前类中都有效
每创建一个对象,就会分配一块独立的空间来存储相关成员变量的信息

  1. 实例变量(不加static修饰):
    调用方法:对象名.属性名。
    内存中占份数:每个对象都有一份。
    内存中位置:堆中。
    初始化的时间:创建对象后,就分配空间,有值。
    销毁的时间:当没有引用指向时,会被垃圾回收器回收。
  2. 类变量(加static修饰):
    调用:类名.属性名。
    内存中占:当前类所有对象共享一份。
    内存中位置:方法区。
    初始化的时间:先有类,才会有对象,类变量的初始化时间早于实例变量。
    销毁的时间:类变量的存活时间,随着类的消亡而消亡,存活时间相较于实例变量要长。
  3. 局部变量: 定义到方法中的变量
    只能在当前方法内有效;
    在使用前已经完成初始化操作,否则报错
    局部变量在完成方法调用后才会完成初始化操作
    当方法执行完毕,就会弹栈消失
    使用final修饰 ,值不能改变

变量区别总结

  1. 声明位置和方法
    1. 静态变量:在类中方法外,并且有static修饰
    2. 实例变量:在类中方法外,没有static修饰
    3. 局部变量:在方法{}中或方法的形参列表、代码块中
  2. 在内存中存储的位置不同
    1. 静态变量:方法区
    2. 实例变量:堆
    3. 局部变量:栈
  3. 生命周期
    1. 静态变量:和类的声明周期一样,因为它的值是该类所有对象共享的,早于对象的创建而存在
    2. 实例变量:和对象的声明周期一样,随着对象的创建而存在,随着对象被垃圾回收而消亡,而且每一个对象的实例变量是独立的
    3. 局部变量:和方法调用的声明周期一样,每一次方法被调用而存在,随着方法执行的结束而消亡,而且每一次方法调用都是独立的
  4. 作用域
    1. 静态变量和实例变量:不谈作用域
      在本类中,唯一的限制,静态方法或静态代码块中不能使用非静态的,其他都可以直接使用。
      在其他类中,能不能使用看修饰符(public、protected,private等)
    2. 局部变量:有作用域,除了作用域就不能使用
  5. 修饰符
    1. 静态变量:public、protected、private、final、volatile等,一定有static
    2. 实例变量:public、protected、private、final、volatile、transient等
    3. 局部变量:final、
      public、protected、private:权限修饰符
      volatile:和多线程有关
      transient:是否序列化,和IO有关
  6. 默认值
    1. 静态变量:有默认值
    2. 实例变量:有默认值
    3. 局部变量:没有,必须初始化
      其中的形参比较特殊,靠实参给它初始化

方法

也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。
把一个功能封装为方法的目的是,可以实现代码重用,从而减少代码量。

静态方法:被static修饰的方法
非静态方法:不被static修饰的方法

方法的定义(声明)、调用:
[权限修饰符] [static] 返回值类型 方法名(形参列表){}
1. 只声明不调用是不会执行的
2. 静态方法使用:类名.方法名 进行调用,如果在本类中可以省略类名
3. 方法的执行顺序与声明顺序无关,只与调用顺序有关
4. 方法可以在任何方法中被调用
5. 方法执行完毕之后,会回到方法的调用处
6. 非静态方法:不在本类中,必须通过对象名.方法名();调用
7. 非静态方法:在本类中,可以省略对象名直接调用 
8. 静态方法不能【直接】引用非静态的方法或者变量,可以通过创建对象的方式间接引用
9. 非静态方法来者不拒,静态或非静态的变量、方法都可以直接使用

static:静态的内容已经随着类的加载而加载,而此时对象可能还没有创建,所以不能使用,对象创建后才分配内存空间

虚方法

可以重写的方法

非虚方法

不可以重写的方法(静态方法、独有方法、使用final修饰的方法、构造器)

递归

指在当前方法内调用自己的这种现象

  1. 直接递归:方法自身调用自己
//求1~100的和
class Test{
	public static void main(String[] args){
		int sum = getSum(100);
		System.out.println("sum=" + sum);
	]
	public static int getSum(int num){
		//出口
		if(num == 1){
			retuen 1;
		}
		//不断地向出口靠近
		return num + getSum(num-1);
	}
}
  1. 间接递归:A调B,B调C,C调A
  2. 注意事项
    1. 递归一定要有条件限制,保证递归能够停止下来,否则会发生栈内存溢出
    2. 在递归中虽然有限制条件,但是递归次数不能太多,否则也会发生栈内存溢出

对代码进行分类管理

  1. 包名:一般采用公司网址的倒叙,所有字母小写(规范)
  2. 不同包下可存在同名类

java.lang 不需要导包
java.sql 数据库相关
java.io IO
java.net 网络编程相关
java.util 工具包

注:只要使用不是本包下的资源,都需要导包
3. 当一个类中需要使用同名的两个类,必然会有一个类使用全路径(全类名)导入,即包名+类名
4. 包名的声明,必须放在代码首行

可变形参

参数的个数可以任意个[0,n]
可变形参采用数组存储实参
一个方法可变参数只能有一个,且必须位于参数列表最后
声明方法:

public class Test{
	public static void main(String[] args){
		sum(1,2,3,4,5,6,7,8,9);
		sum1(3.14,1,2,3,4,5);
	}
	static void sum(int...a){
		for(int i = 0; i < a.length; i++){
			System.out.println(a[i]);
		}
	}
	static void sum1(double b,int...a){
		double sum = 0;
		for(int i:a){//求数组内的和
			sum += i;
		}
		sum += b;//求数组内的和+double
		System.out.println(sum);
	}
}

方法重载

不同方法使用相同方法名

  1. 同一类中,同一方法名,不同的形参列表:数量、顺序、类型
  2. 方法调用时会根据不同的数据类型自动找到最佳匹配的方法
public class Test{
	public static void main(String[] args){
		sum(1,2);
		sum(1.2,1.3);
	}
	static void sum(int a,int b){
			System.out.println(a+b);
	}
	static void sum(double a,double b){
		System.out.println(a+b);
	}
}

命令行参数

  1. run --> eidt configurations -->main class 是自己运行的那个类 --> program arguments
  2. dos窗口 java Test 值1 值2

封装

属性不能直接暴露给外界访问
通俗讲:该隐藏的隐藏,该暴露的暴露
高内聚:类的内部数据操作细节字节完成,不允许外部干涉
低耦合:仅对外暴露少量的方法用于使用
外部类只能由public和default(什么都不写)修饰

修饰符本类本包其他包子类其他包非子类
private(私有的)×××
缺省××
protected (受保护的)×
public(公共的)
/*
	属性不能直接暴露给外界访问
	getXxx()方法进行属性赋值
	setXxx()方法获取属性值,方法带返回值,返回值的类型与属性的类型保持一致
	this:代表当前对象,谁调用就是谁
*/
public class Person{
//属性私有后,不能直接被访问
	private String name;
	private String sex;
	private int age;
	//给成员变量赋值
	public void setSex(String sex){
		this.sex = sex;
	}
	//获取成员变量的值
	public int getSex(){
		return sex;
	}
	public void setAge(int age){
		if(age > 1 && age <= 120){
			//当年龄满足要求的时候,直接赋值
			this.age = age;
		}else{//不满足要求
			this.age = 0;
		}
	}
	public int getAge(){
		return age;
	}
}

public class PersonTest{
	public static void main(String[] args){
		Person p1 = new Person();
		p1.setAge(18);
		p1.setSex("男");
		System.out.println("性别:"+p1.getSex()+"年龄:"+p1.getAge());
	}
}

构造器

快速给成员变量赋值

  1. 每一个类中都会有一个默认的无参构造器,当声明有参的构造器后,默认的无参构造器就会消失
  2. 建议自定义类都手动提供一个无参构造器
  3. 当成员变量与局部变量的名字重复的时候,在成员变量前+this,用于区分:我是成员变量
  4. 构造器(构造函数/构造方法)是可以重载的
  5. 可以用来调用本类中的构造器(根据数据类型进行匹配)(一般多参调少参)
  6. 调用本类构造器必须位于首行
  7. this可以调用成员方法,一般在本类中可以省略this
  8. 每一个构造器的首行,都会有一个默认的隐藏的super();调用父类无参的构造器
  9. 当出现this()调用本类中构造器时,那个默认的super()自动消失
  10. 可以使用super(参数)调用父类有参的构造器
  11. 可以使用super.去调用父类的方法和属性
public class Person{
	private String name;
	private String sex;
	private int age;
	private double height;
	//手动添加无参构造
	public Person(){
	}
//语法:[权限修饰符] 类名(形参列表){}
//3. 当成员变量与局部变量的名字重复的时候,在成员变量前+this,用于区分:我是成员变量
	public Person(String name,String sex,int age){
		this.name = name;
		this.sex = sex;
		this.age =age;
	}
	public Person(String name,String sex,int age,double height){
	//5. 可以用来调用本类中的构造器(根据数据类型进行匹配)
	//6. 调用本类构造器必须位于首行
		this(name,sex,age);
		this.height = height;
	}
	public void show(){
	//7. this可以调用成员方法,一般在本类中可以省略this
		showInfo();
	}
	public void showInfo(){
		System.out.println("姓名:"+name+",性别:"+sex+",年龄:"+age+",身高"+height);
	} 
}

public class PersonTest{
	public static void main(String[] args){
		Person p1 = new Person("张三","男",18);
		p1.showInfo();
		Person p2 = new Person("张三","男",18,1.83);
		p2.showInfo();
	}
}

继承

  1. 使用继承要借助关键字extends
  2. 语法结构:[权限修饰符] 子类 extends 父类{}
  3. 当子类继承父类后就可以使用父类的资源(属性和方法)
  4. this:代指当前对象,当前对象是谁,谁调用就是谁
  5. super:代表从父类继承过来的资源
  6. 当子类没有此资源而父类有时,则使用super 和this 没有区别
  7. 子类在使用资源时(属性、方法)优先在本类中查找,当本类中没有时,才会去父类中查找;一点一点向上找,知道找到Object类
  8. Object类是所有类的父类,如果一个类没有显示的继承另一个类,那么此类默认继承自Object类
  9. 如何快速显示继承关系:在需要查看的类上右键–>Diagrams–>show diagrams(可以通过 空格 添加想要查看的类)

重写

  1. 当父类的方法不能满足子类的需求时,要进行方法的重写
  2. 当子类重写父类的方法是时,访问权限不能比父类方法的访问权限更加严格(>=父类访问权限)
  3. 返回值类型
    1. 当父类的返回值类型是基本类型数据时,则子类必须与父类保持一致
    2. 当父类的返回值类型是引用类型数据时,则子类可以是返回父类,也可以返回子类
  4. 方法重写时,子类的形参必须与父类的形参保持一致,否则就相当于在子类中新增一个方法
  5. 关于异常:子类不能抛出比父类更大的异常(编译时异常有效)
/*
	声明一个动物类
	用于存储各种动物相同的信息
*/
public class Animal{
	String name = "Animal";
	int age = 18;
	public void eat(){
		System.out.println(name+"在吃饭");
	}
	public void call(){
		System.out.println("叫");
	}
}
//2. 语法结构:[权限修饰符] 子类 extends 父类{}
public class Dog extends Animal{
	
	public void lookHome(){
		System.out.println(name+"看家护院");
	}
	//1. 当父类的方法不能满足子类的需求时,要进行方法的重写
	//方法的重写
	public void eat(){
		System.out.println("吃骨头");
	}
}
public class Cat extends Animal{
	int age = 10;
	public void catchMouse(){
		System.out.println(name+"抓老鼠");
	}
	public void showAge(){
	//5. super:代表从父类继承过来的资源	this.age 10					18		
		System.out.println("cat的年龄:"+age+",Animal的年龄:"+super.age);
	}
	pubilc void showName(){
	//6. 当子类没有此资源而父类有时,则使用super 和this 没有区别
	//this:代指当前对象,使用的是从父类继承的资源
	//super:直接使用父类资源
		System.out.println("name: "+ super.name);
	}
}
public class Test{
	public static void main(String[] args){
		Cat cat = new Cat();
		cat.name = "Tom";
		cat.,showAge();
		cat.eat();

		Dog dog = new Dog();
		//8. 子类在使用资源时(属性、方法)优先在本类中查找,当本类中没有时,才会去父类中查找
		dog.eat();
		dog.call();
	}
}

代码块

  1. 成员代码块:用于给成员变量赋值
    每创建一个对象就会执行一次
    早于构造器执行
    按照代码块的书写顺序执行
public class Person{
	String naem;
	int age;
	public Person(){
		System.out.println("无参构造器");
	}
	//成员代码块
	{
		name = "张三";
		age = 18;
		System.out.println("代码块1");
	}
	{
		name = "张三";
		age = 18;
		System.out.println("代码块2");
	}
} 
public class TestPerson{
	public static void main(String[] args){
		Person p = new Person();
		//每创建一个对象就会执行一次
		//早于构造器执行
		
	}
}
  1. 静态代码块:用于给静态变量进行赋值
    静态代码块只会创建一次,再次创建n个对象也不会再执行
    先于构造器执行
    按照代码块的书写顺序执行
public class Student{
	static int age;
	//静态代码块
	static{
		age = 20;
		System.out.println("静态代码块1");
	}
	public Student(){
		System.out.println("无参构造器");
	}
	static{
		System.out.println("静态代码块2");
	}
}
public class Test{
	public static void main(String[] args){
		Student s1 = new Student();
		//静态代码块只会执行一次
		Student s2 = new Student();
	} 
}

成员变量初始化

给成员变量赋值的方法
  1. 默认值
  2. 直接赋值
  3. 代码块赋值
  4. get/set
  5. 构造器赋值
    静态变量:不建议采用构造器赋值,他是属于类的,可以使用“类名.属性”进行赋值
类的初始化
  1. 目的:为类中的静态变量进行赋值
  2. 类的初始化过程在调用一个()方法,而这个方法是编译器自动生成的,编译器会将(1)静态类成员变量的显式赋值语句(2)静态代码块中的语句。这两部分的所有代码,按顺序合并到类的初始化()方法体中
  3. 整个类初始化只会进行一次,如果子类初始化时发现父类没有初始化,会先初始化父类
实例初始化
  1. 目的:为类中非静态成员变量赋值
  2. 编译时自动处理代码,整理出一个()的类初始化方法,还会整理处一个或多个(…)实例初始化方法。一个类有几个实例化方法,由这个类就有几个构造器决定
    1. super()或super(实参列表)这里选择哪个,看原来构造器首行是哪句,没写,默认就是super()
    2. 非静态实例变量的显式赋值语句
    3. 非静态代码块
    4. 对应构造器中的代码
    5. 特别说明:其中 2 和 3 是按顺序合并的,1 一定在最前面 ,4 一定在最后面
  3. 执行特点:
    1. 创建对象时,才会执行
    2. 每new一个对象,都会完成该对象的实例初始化
    3. 调用哪个构造器,就执行它对应的实例初始化方法
    4. 创建子类对象时,父类对应的实例初始化会被先执行,执行父类哪个实例初始化方法,看用super()还是super(实参列表)

多态

多态:一个对象的多种状态
作用:可以让代码更加灵活

  1. 实现多态条件
    1. 有继承
    2. 有方法的重写
    3. 父类的引用指向子类的对象
  2. 多态有两种状态
    1. 编译时状态:=左边
    2. 运行时状态:=右边
  3. 多态创建的对象,能够调用什么方法,要看编译时状态

多态三个点
4. 应用的到形参
5. 多态数组:父类[] arr = {父类对象,子类对象}
6. 多态应用于方法的返回值:public 父类类型 方法名(){return 子类对象();}

public class Animal{
	public void eat(){
		System.out.println("在吃饭");
	}
	public void sleep(){
		System.out.println("睡觉");
	}
}
//1. 有继承
public class Dog extends Animal{
	
	public void lookHome(){
		System.out.println("看家护院");
	}
	//2. 有方法的重写
	public void eat(){
		System.out.println("吃骨头");
	}
}
public class Cat extends Animal{
	public void catchMouse(){
		System.out.println("抓老鼠");
	}
	public void eat(){
		System.out.println("吃鱼");
	}
}
public class Test{
	public static void main(String[] args){
	//3. 父类的引用指向子类的对象
	//	编译时状态 = 运行时桩体
		Animal a = new Dog();
		
	//3.多态创建的对象,能够调用什么方法,要看编译时状态
		a.eat();//子类重写父类的方法。
		//表面上调用的是Animal的eat()方法
		//实际上运行的是Dog对象
		//所以在执行时,执行的是Dog中eat()方法
		
		a.sleep();//从父类继承的方法

		Dog dog = new Dog();
		showEat(dog);
		Cat cat = new Cat();
		showEat(cat);
		
		//创建Animal类型的数组
		//存储dog和cat
		Animal[] animalArr = new Animal[2];
		animal[0] = dog;
		animal[1] = cat;
		for(Animal a:animalArr){
			a.eat();
		}
	}
					//Animal animal = dog;
	public static void showEat(Animal animal){
	//表面上调用的是Animal的eat()方法
		//实际上运行的是Dog对象
		//所以在执行时,执行的是Dog中eat()方法
		animal.eat();
	}
}

多态的向上转型和向下转型

  1. 运行时类型从始至终不会发生改变
  2. 多态的向上转型和向下转型都是针对编译时类型
    1. 向上转型 up casting :Animal animal = new Cat();
      弊端:不能使用子类所独有的资源
    2. 向下转型 down casting:使用子类自己独有的资源的时候
      前提:已经完成了向上转型
  3. 不是所有的类型都可以相互转换,借助于instanceof关键字进行判断
public class Animal{
	public void eat(){
		System.out.println("在吃饭");
	}
	public void sleep(){
		System.out.println("睡觉");
	}
}
public class Cat extends Animal{
	public void catchMouse(){
		System.out.println("猫抓老鼠");
	}
	public void eat(){
		System.out.println("猫吃鱼");
	}
}
public class Dog extends Animal{
	public void lookHome(){
		System.out.println("狗看家");
	}
	public void eat(){
		System.out.println("狗吃肉");
	}
}
public class Test{
	public static void main(String[] args){
	//1. 向上转型 up casting :Animal animal = new Cat();
	//	弊端:不能使用子类所独有的资源
		Animal animal = new Cat(); 
		animal.eat();
	//2. 向下转型 down casting:使用子类自己独有的资源的时候
	//	前提:已经完成了向上转型
		Cat cat = (Cat)animal;
		cat.catchMouse();
	}
}	

instanceof

  1. 判断左边的对象是否属于右边的类型
  2. 小的对象可以是属于大的类型,必须有继承关系
public class Animal{
	public void eat(){
		System.out.println("在吃饭");
	}
	public void sleep(){
		System.out.println("睡觉");
	}
}
public class Cat extends Animal{
	public void catchMouse(){
		System.out.println("猫抓老鼠");
	}
	public void eat(){
		System.out.println("猫吃鱼");
	}
}
public class Dog extends Animal{
	public void lookHome(){
		System.out.println("狗看家");
	}
	public void eat(){
		System.out.println("狗吃肉");
	}
}
public class Test{
	public static void main(String[] args){
		Animal animal = new Animal();
		Cat cat = new Cat();
		System.out.println(animal instanceof Animal);//true
		System.out.println(cat instanceof Animal);//true
		String s = "你好";
		System.out.println(s instanceof Object);//true
		//System.out.println(s instanceof Animal);报错
		Dog dog = new Dog();
		//System.out.println(dog instanceof Cat);报错

		showEat(dog);
		showEat(cat);
	}
	public static void showEat(Animal animal){
		animal.eat();
		if(animal instanceof Cat){
			Cat cat = (Cat)animal;
			cat.catchMouse();
		}
		if(animal instanceof Dog){
			Dog dog = (Dog)animal;
			dog.lookHome();
		}
	}
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值