面向对象
一、对象
类=方法+属性
面向过程:
步骤清晰简单,第一步做什么,第二部做什么,适合处理一些较为简单的问题
面向对象:分类的思维,思考问题需要哪些分类,对这些分类进行单独思考,最后才对某个分类的细节进行面向过程,适合处理复杂的问题,需要多人协作时采用面向对象
面向对象编程本质:以类的方式组织代码,以对象的方式封装数据
三大特性:
封装
继承
多态
扩展
break 跳出switch和结束循环
return 表示一个方法的结束
二、类与对象的创建
1、创建与初始化对象
2、构造器
构造器就是构造方法
不写返回值类型,名字与类名一样,不能够return,不能写void
用来实现类的实例化,完成对象初始化
类中不定构造方法时,系统会自动为该类生成无参数的构造方法
作用:
1、使用new关键字,本质是在调用构造器,必须要有构造器
构造器一般用来初始化值
2、而一旦定义了有参构造,无参构造(隐藏了)就必须显示定义,不能删掉,否则在实例化对象的时候会出错(类似方法的重载)
3、方法的重载:根据参数来调用方法,一个类中可以有多个相同名字的方法,但方法的参数必须不同
方法的重写:本质是覆盖,子类的方法体和父类的不一样,子类的方法声明和方法体一样,子类可以通过重写隐藏已继承的方法
子类中定义一个方法,这个方法的类型可以时父类的方法的类型的子类型,也可以和父类的方法一致,且名字,参数个数、类型要和父类完全相同
重写可以改变父类的状态和行为,隐藏了其方法和成员变量,要向调用,必须用关键字super
扩展:this 只能用在实例方法和构造方法中,不能用在类方法
想访问被子类隐藏的变量和方法则:super.变量名或者super.方法名()
三、创建对象与内存分析
堆:存放new的数组和对象,栈:存放基本变量类型和引用,方法
先加载类的信息到方法区,main()最先入栈;然后执行Pet dog=new Pet(),加载Pet类的信息,dog是引用常量,通过new实例化对象dog就有了pet类模板中的属性和方法;赋值:会先在常量池中找(字符串都存放在常量池中),如果有直接赋值,没有则开辟一块区域新建一块
四、封装详解
1、封装:数据的隐藏,禁止直接访问一个对象中数据的实际表示,而通过操作接口来访问
2、封装最主要是针对属性,方法用的比较少
3、属性私有:加个private关键字(private int age;)
属性私有后不能直接调用,于是提供一些可以操作这个属性的方法,入一些public的get/set方法
set方法要有参数且方法体里面可以做一些安全性判断:判断年龄是否符合实际生活中的年龄大小
4、封装意义
提高程序的安全性,保护数据
隐藏代码的实现细节
统一接口
系统可维护性增加了
五、继承
1、继承是类和类的关系;
一个为子类(派生类),一个为父类(基类),且只有单继承即一个子类只能由一个父类,一个父类可以有多个子类;由关键字extends表示
2、所有类都是object类的子类
3、super
注意点:
super调用父类的构造方法,必须在构造方法的第一个
super必须只能出现在子类的方法或者构造方法中
super和this不能同时调用构造方法
super和this区别
代表的对象不同:this本身调用者这个对象,super本身父类对象的应用
前提:this没有继承时也可以使用,super只有在继承条件下才能使用
构造方法:this()本类的构造,super()父类的构造
比如:
可以在子类中调用父类的属性和方法
子类调用父类属性的方法要由参数类型和参数名
子类会继承父类的构造器,且父类的构造器必须在子类构造器的前一行;
在子类中,父类构造器:super();一般是隐藏的
会发现在student类实例化后,运行结果是先出现父类的构造方法,再出现子类的构造方法
六、方法的重写
1、重写需要由继承关系,子类重写父类的方法;
方法名、参数列表必须相同;
修饰符可以扩大,不能缩小如private可以扩大public;
重写异常抛出范围不能大于父类,如ClassNotFoundException不能扩大为Exception
静态方法是跟类方法有关,非静态方法是跟对象有关
静态方法:
方法的调用只和左边有关,B b=new A();左边的类是父类B,是A的上转型对象
非静态方法(重写):
A重写B的test(),静态不可以重写
子类调用父类的方法,但是重写了,方法体和父类的不一样
七、多态
1、多态是方法的多态,属性没有多态。
同一个方法中根据对象的不同,采用多种不同的行为方式。
一个对象的实际类型是确定的,但是指向对象的引用的类型由很多。
父类和子类有联系 类型转换异常:ClassCastException。
2、多态存在的条件:
- 有继承关系
- 子类重写父类的方法(static 方法属于类;final修饰常量;private;这三个都无法重写
- 父类引用指向子类对象(参考六的静态方法调用):Father f1=new Son()
3、这里的S2.eat()调用会报错,因为eat()是子类student独有的,所以要强制转换(高转低):((student)S2).eat(),这样才不会报错
八、instanceof(引用类型的转换)
1、可以判断一个对象是什么类型
可以判断两个类之间是否存在父子关系
2、object是student类的对象,不是Object类,所以object instanceof student 为true
3、A(对象)instanceof B(类)结果为boolean
4、引用类型 变量名 = new 类名1();
对象 instanceof 类名2;
Step1: 引用类型是否可以强制转换为类名2
可以:Step2;
不可以:编译报错,结束
Step2:类名1 是否为 类名2 的子类或类(本身)
是:true
不是:false
也就是说引用类型若与类名2存在继承关系或者能强制转换成类名2,则不会编译错误;同时类名1如果是类名2子类或本身,则最后结果为true
5、父类引用指向子类对象:Father f1=new Son()
父类转换成子类,向下转型
子类转换成父类,向上转型,方法会丢失
九、static详解
1、age是静态(static)变量,可以用类直接调用:System.out.println(Student.age);
静态变量也可以用对象调用
非静态变量只能用对象调用
静态方法可以通过类调用:Student.go()或者go()
非静态方法要先创建一个对象,再调用:new student().run()
2、匿名代码块是创建对象的时候自动创建了,类不会直接调用,而且再构造器之前,可以在此处赋初始值。
静态代码块是类一加载就执行,永久只执行一次
第一执行结果顺序是静态代码块,匿名代码块,构造方法,接下来在执行的顺序为匿名代码块,构造方法
3、静态导入包:导入其他类的静态方法:
import static java.lang.Math.random;导入这个random方法后,就可以直接用random()不需要用类调用:Math.random()
4、final修饰的类不能被继承,final修饰的方法不允许重写
十、抽象类
abstract修饰的方法和类为抽象方法和抽象类
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
抽象类不能用new关键字,只能让子类继承的
抽象方法,只有方法的声明,没有方法的实现,只能让子类实现的,让子类去重写抽象方法
子类继承抽象类,必须实现抽象类没有实现的抽象方法,否则子类也要声明为抽象类
十一、接口
1、普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有,只是要通过子类实现
接口:只有规范,自己无法写方法,都要有实现类;约束和实现分离:面向接口编程
2、接口中方法默认为public abstract(一般public abstract可以省略)
实现类中要实现接口的定义,必须重写方法,否则会报错
抽象类中还有方法的实现,接口中只有方法的定义,然后再通过实现类重写接口中的方法
接口是多继承,一个实现类可以implements多个接口
3、接口里定义的属性都是常量,是一个静态的常量:public static final
4、接口不能被实例化,接口中没有构造方法
十二、内部类
参考文章
1、成员内部类
内部类如何定义?通过外部类来实例化内部类:Outer.Inner inner=outer.new Inner()
这就是成员内部类,成员内部类可以访问外部类所有属性和方法,外部类要访问内部类的属性和方法,必须先实例化成员内部类
内部类可获得外部类的私有属性
2、静态内部类
再成员内部类多加了个static,静态内部类只能访问外部类的静态成员变量和方法(包括私有静态)
3、匿名内部类
一个Java文件里面只能由一个public class但可以有多个class
没有名字初始化类,不用将实例保存到变量中,只在堆内存中使用对象,不在栈内存中使用变量引用,节省内存
适用于当一个内部类需要继承或者实现,而且只使用一次的时候
4、局部内部类是定义在代码块里的一个内部类,比如在方法里定义一个内部类
局部内部类不能被public,private,protected,static修饰,但可以被final修饰