面对对象(OOP)
面对过程的思想:
- 步骤清晰简单,第一步作什么,第二步作什么…
- 面对过程适合处理一些较为简单的问题
面对对象的思想:
- 物以类聚,分类的思维模式,思考问题,首先会去解决这个问题需要那些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思考
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面对对象的思路来分析整个系统。但是,具体到微观操作,依然需要面对过程的思路去处理
面向对象的本质就是:以类的方式组织代码,以对象的形式封装数据
抽象思想
三大特性:
- 封装
- 继承
- 多态
从认识论角度考虑是先有对象后有类。对象,是具体的事物。类是抽象的,是对对象的抽象
从代码运行角度考虑是先有类再有对象,类是对象的模板
方法的回顾
- 方法的定义
- 修饰符
- 返回值类型
- 方法名
- 参数列表
- 异常抛出
- break和return的区别
- 方法的调用
- 静态方法
- 非静态方法
- 形参和实参
- 值传递和引用传递
- this关键字
public class Demo01 {
public static void main(String[] args) {
//静态方法的调用
Student.say();
//非静态方法的调用
Student student = new Student();
student.talk();
}
//静态方法和类一起加载
//静态方法不能调用非静态方法
public static void a(){
//b();
}
//非静态方法,类实例化之后才存在
//非静态方法可以调用静态方法
public void b(){
a();
}
}
值传递和引用传递?
类和对象的关系
- 类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物,比如说:动物,车
- 对象是抽象概念的具体实例
- 张三就是人的一个具体实例,张三家里的狗旺财就是一个具体实例
- 能够展现出特点,展现出功能的是具体的实例,而不是一个抽象的概念
我们将这种思想转化为代码实现
创建和初始化对象
- 使用new关键字来创建对象
- 使用new关键字来创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
- 类中的构造器也叫构造方法,是在进行创建对象时必须调用的,并且构造器有以下两个特点:
- 必须和类的名字相同
- 必须没有返回值,也不能写void
- 构造器必须掌握
//学生类
public class Student01 {
//属性:字段
String name;//默认是null
int age;//默认是0
//方法
public void study(){
//this表示当前这个类
//this.name表示当前这个类中的name属性
System.out.println(this.age+"岁的"+this.name+"在学习");
}
}
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//类抽象的,实例化
//类实例化之后会返回一个自己的对象
//student01对象就是一个Student01类的具体实例
Student01 xm = new Student01();
Student01 xh = new Student01();
xm.name="小明";
xm.age=26;
xm.study();
xh.study();
}
}
//一个项目应该只存在一个main方法
//alt+insert快捷键
public class Application {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Person nihao = new Person("nihao");
System.out.println(nihao.name);
}
/*
* //类抽象的,实例化
//类实例化之后会返回一个自己的对象
//student01对象就是一个Student01类的具体实例
Student01 xm = new Student01();
Student01 xh = new Student01();
xm.name="小明";
xm.age=26;
xm.study();
xh.study();
* */
}
public class Person {
String name;
//无参构造
//实例化初始值
//两个作用:
//1、使用new关键字,必须要有构造器
//2、用来初始化值
public Person(){
this.name="qiangJiang";
}
//有参构造
//一旦定义有参构造,就一定要显示定义无参构造
//this.name代表类的属性name
//name代表构造器参数name
public Person(String name){
this.name=name;
}
}
类和对象
面对对象的三大特性
封装
- 该露的露,该藏的藏
- 我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉。低耦合:仅仅暴露少量的方法给外部使用
- 封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而因通过操作接口来访问,这称为信息隐藏
记住这句话就够了:属性私有,get/set
//封装:大多数都是对属性来说的,
public class Student02 {
//属性私有
//姓名
private String name;
//学号
private String id;
//年龄
private int age;
//提供一些可以操作这些属性的方法
//提供pubilc的get/set方法
//get:获得这个属性,要有返回值
public String getId() {
return id;
}
//set:给这个属性赋值,不用返回值
public void setId(String id) {
this.id = id;
}
//get:获得这个属性,要有返回值
public int getAge() {
return age;
}
//set:给这个属性赋值,不用返回值
public void setAge(int age) {
if (0<age && age<120){
this.age = age;
}else {
System.out.println("输入的年龄不真实");
this.age = 0;
}
}
//get:获得这个属性,要有返回值
public String getName(){
return this.name;
}
//set:给这个属性赋值,不用返回值
public void setName(String name){
this.name=name;
}
//学习()
//睡觉()
}
public class Application {
public static void main(String[] args) {
Student02 st2 = new Student02();
st2.setName("秦疆");
System.out.println(st2.getName());
st2.setAge(121);
System.out.println(st2.getAge());
}
}
继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
- 私有的不能被继承
- extends的意思是扩展。子类是父类的扩展
- java中类只有单继承,没有多继承
- 继承是类和类之间的一种关系,除此之外还有依赖、组合、聚合等
- 继承关系的两个类,一个为子类(派生类)一个为父类(基类)。子类继承父类,使用extends关键字
- object类,在java中所有的类都默认继承object类
- super
- 方法的重写
super注意点:
- super是调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
this:
- 代表的对象不同:this:本身调用者这个对象,super:代表父类对象的引用
- 前提不一致:this:没有继承也可以使用,super:只能在继承条件下才可以使用
- 调用的构造方法不同:this():本类的构造,super():父类的构造
//继承
//Person 人
//私有的东西无法被继承
public class Person {
public Person() {
System.out.println("我是你爸的无参构造器");
}
public Person(String name) {
this.name = name;
}
protected String name ="kuangsheng";
private int money = 1000;
public void say(){
System.out.println("Person说了一句话");
}
public int getMoney() {
return money;
}
public void print(){
System.out.println("Person");
}
public void setMoney(int money) {
this.money = money;
}
}
//Student is 人
public class Student extends Person{
public Student() {
//隐藏代码:子类的无参构造默认调用了父类的无参构造
super();//调用父类的构造器必须位于子类的第一行
//super("张三");
System.out.println("我是儿子的无参构造器");
}
private String name = "qinjiang";
public void test(String name){
System.out.println(name);//秦疆
System.out.println(this.name);//qinjiang
System.out.println(super.name);//kuangsheng
}
public void print(){
System.out.println("Student");
}
public void test1(){
print();
this.print();
super.print();
}
}
public class Application {
public static void main(String[] args) {
Student student = new Student();
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%");
student.test("秦疆");
System.out.println("**********************");
student.test1();
}
}
方法的重写:需要有继承关系,子类重写父类的方法
当一个类继承了另一个类时,可以对父类的方法进行重写,就是说,对原来的方法进行一个覆盖,改变它的方法体
- 方法名一定要相同
- 参数列表必须相同
- 修饰符:可以扩大,但是不能缩小
- 抛出的异常:范围,可以被缩小,但是不能扩大
重写,子类的方法和父类的方法必须要一致:方法体不同
为什么需要重写:
- 父类的功能子类不一定需要,或者不一定满足
多态
- 即同一个方法可以根据发送对象的不同而采用多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型是很多
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象 Father father = new Son()
注意多态是方法的多态,没有属性的多态
ClassCastException:类型转换异常
以下方法不能被重写:
- static 修饰的方法
- final 常量
- private 修饰的方法
public class Person {
public void run(){
System.out.println("Person我跑的飞起");
}
}
public class Student extends Person{
@Override
public void run() {
System.out.println("Student我就要飞起来了");
}
public void eat(){
System.out.println("Student正在吃东西");
}
}
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//可以指向的引用类型就不确定了
//父类的引用指向子类
//Student 能调用的方法都是自己的或者继承父类的
Student s1 = new Student();
//Person 父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
//对象能执行那些方法,主要看对象左边的类型,和右边关系不大
s1.run();
s2.run();//子类重写了父类的方法,执行子类的方法
s1.eat();
//s2.eat();
}
}
instanceof:可以判断两个类是否有父子关系
//类型之间的转换:父 子
//高 低
Person st = new Student();
//st.go();报错不能这样调用,因为Person没有这个方法
//student将这个对象转换为Student类型,我们就可以使用Student类型的方法了
Student st1 = (Student) st;
st1.go();
//子类转换为父类,可能丢失自己本来的一些特有方法
Student student1 = new Student();
student1.go();
//子类转换为父类
Person person1 = student1;
//person1.go();报错
static关键字
public class Student {
private static int age;//静态变量
private Double score;//非静态变量
public void run(){
//非静态方法可以调用静态方法
}
public static void go(){
//静态方法不可以掉用非静态方法,从加载的顺序可以看出
}
public static void main(String[] args) {
Student st1 = new Student();
System.out.println(st1.age);
System.out.println(Student.age);
System.out.println(st1.score);
//System.out.println(Student.score);出错
Student.go();
//Student.run();出错
st1.run();
}
}
public class Person {
static{
//静态代码块,只执行一次
System.out.println("静态代码块");
}
{
System.out.println("匿名代码块");//创建对象就会执行
}
public Person() {
System.out.println("构造方法");//创建对象就会执行
}
//三者的执行顺序:静态代码块->匿名代码块->构造方法
public static void main(String[] args) {
Person person = new Person();
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Person person1 = new Person();
}
}
抽象类
- abstract修饰符可以用来修饰方法也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明是抽象类
- 抽象类不用通过new关键字来创建对象,它是用来让子类继承的
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
//abstract 抽象类 类:extends 单继承,,,,,接口可以多继承
public abstract class Action {
//不能new这个抽象类,只能通过子类去实现它
//抽象类可以写普通方法
//抽象方法必须要在抽象类中
//抽象的抽象
//约束,有人帮我们实现
//abstract 只有方法名字,没有方法的实现
public abstract void doSomething();
//思考题:抽象类有构造方法吗?抽象类存在的意义是什么?
//抽象类有构造方法
}
接口
普通类:只有具体实现
抽象类:具体实现和抽象方法(规范)都有
接口:只有抽象方法(规范)自己无法写方法,专业的约束,约束和实现分离:面向接口编程
- 接口就是规范,定义一组规则,体现了现实世界中“如果你是…则必须能…“的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须干掉坏人
- 接口的本质就是锲约,就像我们人间的法律一样,制定好后大家都遵守
- OOP的精髓,是对对象的抽象,最能体现这一点就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言,就是因为设计模式就是研究如何合理的去抽象
声明类的关键字是class,声明接口的关键字是Interface
public interface UserService {
//接口中的所有定义其实都是抽象的 public abstract
//public abstract void run(String name);
//void run(String name);这样定义的和上面的是一样的
//所有的属性都是常量,public static final 修饰,,,,但是接口中一般都不会定义属性
int AGE = 99;
void add(String name);//增
void delete(String name);//删
void update(String name);//改
void query(String name);//查
}
//类可以实现接口,通过Implements
//实现了接口中的了类,就要重写接口中的方法
//接口可以多继承
public class UserServiceImpl implements UserService,TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
作用:
- 约束
- 定义一些方法,让不同的人实现 10->1
- public abstract
- public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口,
- 必须要重写接口中方法
内部类(必修)
内部类就是在一个类的内部再定义一个类,比如:A类中定义了B类,那么B类相对A类来说就成为内部类,而A类相对B类来说就是外部类了
- 成员内部类
- 静态内部类
- 局部内部类:在方法里面再创建一个类
- 匿名内部类
//内部类
public class Outer {
private int id;
public void outer(){
System.out.println("!!!这是外部类的方法!!!");
}
public class Inner{
public void inner(){
System.out.println("###这是内部类的方法###");
}
//获取外部类的所有属性和方法
public void getId(){
System.out.println(id);
}
//static的内部类不能访问外部非static属性
}
}
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过这个外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.inner();
}
}
public class Test {
public static void main(String[] args) {
//没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}