面向对象编程
OO:面向对象
OOP:面向对象编程(Object-Oriented Programming,OOP)
1.初识面向对象
-
面向过程思想:
-
步骤清晰简单,第一步做什么,第二步做什么
-
面向对象思想:
- 分类的思维模式:首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思考。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
-
面向对象本质:以类的方式组织代码,以对象的组织(封装数据)
-
抽象
-
三大特性:
-
封装
-
继承
-
多态
-
2.方法回顾和加深
/*
修饰符 返回值类型 方法名(...){
//方法体
return 返回值;
}
*/
public String sayHello(){
return "hello";
}
public int max(int a,int b){
return a>b?a:b;//三元运算符
}
3.对象的创建分析
-
类与对象的关系
- 类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物
- 对象是抽象概念的具体实例
-
使用new关键字创建对象
-
使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
-
类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的,并且构造器有以下特点:
- 必须和类的名字相同
- 必须没有返回值,也不能写void
public class Demo02 { public static void main(String[] args) { //类:抽象类,实例化 //类实例化后会返回一个自己的对象 //student对象就是一个Student类的具体实例 Student s1=new Student(); s1.name="小明"; s1.age=14; Student s2=new Student(); s2.name="小红"; s2.age=13; } } class Student{ String name;//默认值:null int age;//默认值:0 void study(){ System.out.println("学习学习学习习"); } }
-
构造方法
idea中 alt+insert可以自动生成构造器
- 和类名相同
- 没有返回值,且不加void关键字
- new本质在调用构造方法
- 初始化对象的值
- 定义有参构造之后,如果想要使用无参构造,显示地定义一个无参构造
public class Demo03 { public static void main(String[] args) { Person person1 =new Person(); System.out.println(person1.name); Person person2 =new Person("king"); System.out.println(person2.name); } } class Person { //一个类即使什么都不写,它也会存在一个方法 //显示的定义构造器 String name; //实例化初始值 //1.使用new关键字,本质是在调用构造器 public Person(){ //无参构造器 this.name ="queen"; } //有参构造器,一旦定义有参构造,无参构造器必须显示 public Person (String name){ this.name=name; } }
-
堆、栈、方法区的关系
小结
-
类与对象
- 类是一个模板:抽象;对象是一个具体的实例
-
对应的引用
- 引用类型:八大基本数据类型
- 对象是通过引用来操作的:栈---->堆
-
属性:字段Field 成员变量
- 默认初始化:
- 数字:0;0.0
- char:u0000
- boolean:false
- 引用:null
- 默认初始化:
-
对象的创建和使用
- 必须使用new关键字创建对象
- 对象的属性
- 对象的方法
-
类
- 静态的属性-----属性
- 动态的行为-----方法
4.面向对象的三大特性
- 封装(追求:高内聚,低耦合)
- 数据的隐藏:通常,应该禁止访问一个对象中数据的实际表示,而应该通过接口来访问,这称为信息隐藏
- 属性私有:set/get
public class Demo05 {
public static void main(String[] args) {
Student1 s1=new Student1();
s1.setName("小明");
System.out.println(s1.getName());
s1.setId(11);
System.out.println(s1.getId());
}
}
class Student1{
private String name;//名字
private int id;//学号
private char sex;//性别
//用set/get方法来访问private变量
String getName(){
return this.name;
}
void setName(String name){
this.name =name;}
int getId() {
return id;
}
void setId(int id) {
this.id = id;
}
//alt+insert 自动生成set/get方法
char getSex() {
return sex;
}
void setSex(char sex) {
this.sex = sex;
}
}
-
继承
*Ctrl+H:
- 继承的本质是对某一批类的抽象
- 被final继承的类无法有子类
-
extends---->子类是父类的扩展
-
继承是类与类之间的一种关系
- Java中只有单继承,没有多继承
-
子类(派生类),父类(基类)
public class Demo06 { public static void main(String[] args) { Teacher1 t1 =new Teacher1(); t1.say();//继承父类,拥有父类的方法(private不可) } } class Person1{ void say(){ System.out.println("学习学习"); } } class Teacher1 extends Person1{ }
-
-
object 类
- java中默认所有的类直接或者间接继承Object类
-
super
- super.name 指的是父类的变量
- super();子类调用父类的构造器一定要在子类的第一行!否则会报错
- 注意点
- 1.super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
- this VS super
- this:本身调用的这个对象;没有继承也可以使用;this();本类的构造
- super:代表父类对象的应用;只能在继承条件下才可以使用;super();父类的构造
-
方法重写
注意:静态方法和非静态方法的差别很大!
-
需要有继承关系,子类重写父类的方法
-
方法名相同;参数列表相同;修饰符范围可以扩大但是不可以缩小;方法体不同
-
抛出的异常,范围可以缩小但是不能扩大
-
为何重写:父类功能子类不一定需要或者不一定满足
public class Demo06 { public static void main(String[] args) { A a=new A(); a.test();//A--->test() B b=new B(); b.test();//B--->test() A a2=new B();//向上转型 a2.test();//B--->test() } } //重写都是方法的重写和属性无关 class A{ void test(){ System.out.println("A--->test()"); } } class B extends A{ void test(){ System.out.println("B--->test()"); } }
-
*修饰符优先级:
public—protected—default—private
-
多态
-
同一方法根据发送对象的不同而采取多种不同的行为方式
-
一个对象的实际类型是确定的,但是可以指向对象的引用的类型有很多种
-
条件:
- 有继承关系
- 子类重写父类的方法
- static;final;private方法不能重写
- 父类引用指向子类对象
-
注意:
- 多态是方法的多态,属性没有多态性
- instanceof
- X instanceof Y ------如果有父子关系就输出true---------XY平级则报错----------无父子关系就输出false
- 类型转换异常:ClassCastException
- 向下强制转换:(转换类型)对象
- 子类转换为父类,可能丢失一些自己本来的一些方法
-
-
static:
public class Demo07 { public static void main(String[] args) { Box b1=new Box(); /* 运行结果: 静态代码块 匿名代码块 构造方法 */ Box b2=new Box(); /* 运行结果: //静态代码块只执行一次 匿名代码块 构造方法 */ Box.age2=41;//静态变量可以直接用类名来point b1.age1=14; b1.age2=42; } } class Box{ { System.out.println("匿名代码块"); } static { System.out.println("静态代码块"); } Box(){ System.out.println("构造方法"); } int age1; static int age2; }
- import java.lang.Math;//导入math包
- import static java.lang.Math.random;//静态导入包,,后续程序就无需写Math.random()可以直接写random()
5.抽象类
-
abstract修饰符可以用来修饰方法也可以用来修饰类。抽象方法/抽象类
-
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
-
抽象类不能用new关键字来创建对象,要用子类继承
-
抽象方法,只有方法的声明,没有方法的实现,需要用子类实现!子类继承抽象类,必须实现抽象类没有实现的抽象方法,否则子类也要声明为抽象类
public class Demo08 { public static void main(String[] args) { //Action a=new Action();报错 Do d1=new Do(); } } //类单继承;接口多继承 abstract class Action{ abstract void doSomething(); } class Do extends Action{ void doSomething() { } }
6.接口
- 接口的本质是契约
- OO的精髓,是对对象的抽象,最能体现的就是接口(为什么我们讨论设计模式都只针对具备了抽象能力的语言(C++,java,C#等),就是因为设计模式所研究的实际就是如何合理地去抽象)
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
//接口:无法写方法,约束和实现分离
//接口都需要实现类
interface Service{
//接口中所有定义都是抽象的
void run(String name);
}
interface Service2{
void jump(String name);
}
//实现接口的类,就需要重写接口中的方法
class User implements Service,Service2{
//接口里的抽象方法进行实现,可用快捷键Alt+Enter
public void run(String name){
}
public void jump(String name) {
}
//常量的定义:public static final,一般不会在接口中去定义常量
}
7.内部类和OOP实战
定义:一个类的内部再定义一个类,A类中定义一个B类,B类相对于A而言是内部类,A类相对于B而言是外部类
-
成员内部类
public class Demo10 { public static void main(String[] args) { Outer outer = new Outer(); //通过这个外部类来实例化内部类 Outer.Inner inner = outer.new Inner(); inner.in(); inner.getId(); } } class Outer{ private int id=111; void out(){ System.out.println("这是外部类的方法"); } class Inner{ void in(){ System.out.println("这是内部类的方法"); } //获得外部类的私有属性 void getId(){ System.out.println(id); } } }
-
静态内部类
-
局部内部类
class Outer{ //局部内部类 void method(){ class Inner{ void in(){ } } } }
-
匿名内部类
public class Demo10 { public static void main(String[] args) { //没有名字初始化类,不用将实例保存到变量中 new Outer().eat(); } } class Outer{ void eat(){ System.out.println("eat"); } }