面向对象编程(Object-Oriented Programming,OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
三大特性:封装、继承、多态
从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
从代码运行角度考虑是先有类后有对象。类是对象的模板。
类是一种抽象的数据类型,它是对某一类事物的整体描述/定义,但是并不能代表某一个具体的事物。
动物、植物、手机、电脑…… Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为。
对象是抽象概念的具体实例
张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例。 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象概念。3.创建与初始化对象
使用new关键字创建对象
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
必须和类的名字相同必须没有返回类型,也不能写void
package com.oop.demo02;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//new实例化一个对象
Person person=new Person("snow");
System.out.println(person.name);//默认值null
}
}
package com.oop.demo02;
public class Person {
//一个类即使什么都不写,它也会存在一个默认方法(构造器)
//显示的定义构造器,无参构造器,可以初始化信息。
String name;
//实例化初始值
//1.使用new关键字,必须要有构造器,本质是调用构造器。
//2.构造器用来初始化值
public Person() {
}
public Person(String name) {
this.name = name;
}
//IDEA用alt+insert快捷键自动生产构造器
}
3.封装
我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,
不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。
优点:
提高代码的安全性。
提高代码的复用性。
“高内聚”:封装细节,便于修改内部代码,提高可维护性。
“低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
属性私有,get/set。注意:封装一般是对于属性封装,很少对于方法。
//类 private私有的和public公共的相对,封装的核心:private私有
public class Student {
//属性私有,添加private修饰符
private String name;//名字
private int id;//学号
private char sex;//性别
private int age;//年龄
//提供一些可以操作属性的方法
//提供一些public的gat、set方法
//get 获得这个数据
public String getName(){
return this.name;
}
//set 给这个数据设置值
public void setName(String name){
this.name=name;
}
//alt+insert快捷键生成get/set
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<120&&age>0){
this.age = age;
}else {
this.age=3;
}
}
}
public class Application {
public static void main(String[] args) {
Student s1=new Student();
s1.setName("snow");
System.out.println(s1.getName());
s1.setAge(999);//年龄999岁是不合法
System.out.println(s1.getAge());
}
}
4.继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
extends的意思是”扩展”,子类是父类的扩展。
Java中类只有单继承,没有多继承。一个儿子只能有一个爸爸,一个爸爸可以用多个儿子。
继承是类和类之间的一种关系。除此之外类和类之间的关系还有依赖、组合、聚合等。
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
子类和父类之间,从意义上讲应该具有”is a“的关系。
public class Person {
private int money=10_0000_0000;
public void say() {
System.out.println("你好");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
public class Student extends Person{
//Ctrl+H 查看继承关系
}
四种修饰符的作用域
- public 表明该成员变量或方法对所有类或对象都是可见的,所有类或对象都可以直接访问。protected 表明成员变量或方法对该类自身与它在同一个包中的其他类,在同一包和其他包中的该类的子类都可见。default 表明该成员变量或方法只有自己和与其位于同一包内的类可见。若父类与子类位于同一包内,则子类对父类default成员变量或方法都有访问权限;若父类与子类位于不同的package内,则没有访问权限。private 表明该成员变量或方法是私有的,只有当前类对其具有访问权限,除此之外的其他类或者对象都没有访问权限。
在Java中,所有的类都直接或间接继承Object类。
4.2 super 类super用来调用父类的属性和方法。
public class Person {
protected String name="snow";
public void print(){
System.out.println("Person");
}
}
public class Student extends Person{
//Ctrl+H 查看继承关系
private String name="雪乡";
public void print(){
System.out.println("Student");
}
public void test1(){
print();
this.print();
super.print();
}
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
super注意点:
super调用父类的构造方法,必须在构造方法的第一个super必须只能出现在子类的方法或者构造方法类super和this不能同时调用构造方法!因为构造方法必须在第一个。
public class Person {
public Person() {
System.out.println("Person无参构造器执行了");
}
}
public class Student extends Person{
//隐藏代码:调用了父类构造器
public Student() {
super();//调用父类构造器,必须要在子类构造器的第一行
System.out.println("Student无参构造器执行了");
}
}
super 和 this区别:
代表对象不同:
this:本身调用者这个对象
super:代表父类对象的应用
前提:
this:没有继承也可以使用
super:只能在继承条件才可以使用
构造方法:
this();本类的构造
super();父类的构造
4.3 方法重写重写的前提:重写需要有继承关系,是子类重写父类的方法!重写都是重写类的方法和属性无关
注意事项:
方法名必须相同参数列表必须相同在非静态方法中,子类可以重写父类的方法。修饰符:范围可以扩大但不能缩小,比如父类方法修饰符是 protected,子类重写的方法修饰符可以是protected也可以是public,但是不能是作用域小的修饰符。抛出的异常:范围可以被缩小,但不能扩大。比如父类方法的异常是Exception,那子类重写的方法异常就可以是ClassNotFoundException。
重写,子类的方法和父类的方法必须一致,方法不同。
为什么需要重写?
- 父类的功能字类不一定需要,或不一定满足快捷键 Alt +Insert : override
子类和父类的方法是静态的情况:
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
public class A extends B{
public static void test(){
System.out.println("A=>test()");
}
}
public class Application {
public static void main(String[] args) {
//方法的调用只和赋值符左边,定义的数据类型有关。
A a =new A();
a.test();//显示A=>test()
//父类的引用指向了子类
B b=new A();
b.test();//显示B=>test()
}
}
子类和父类的方法非静态:
public class B {
public void test(){
System.out.println("B=>test()");
}
}
public class A extends B{
//Override 重写
//快捷键Ait+Insert,选择Override重写。
@Override//注解:有功能的注释。
public void test() {
System.out.println("A=>test()");
}
}
public class Application {
//静态方法和非静态的方法区别很大!方法重写只在非静态方法中可以实现。
public static void main(String[] args) {
A a =new A();
a.test();//显示A=>test()
B b=new A();//在非静态方法中,子类可以重写父类的方法。
b.test();//显示A=>test()
}
}
5.多态
动态编译:类型,可扩展性。
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
5.1 多态存在的条件- 有继承关系 - 子类重写父类方法 - 父类引用指向子类对象 Father f1=new Son()
public class Person {
public void run(){
System.out.println("run");
}
public class Student extends Person{
public void run(){
System.out.println("son");
}
public void eat(){
System.out.println("est");
}
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//new Person();
//可以指向的引用类型就不确定了:父类的引用指向子类
Student s1=new Student();
//Person 父类型,可以指向子类,但是不能调用子类独有的方法。
Person s2 = new Student();
Object s3 =new Student()
//子类重写了父类的方法,执行子类的方法。
s2.run();//显示son
//Student能调用的方法都是自己的或者继承父类的!
s1.run();//显示son
s1.eat();//显示eat
//对象能执行那些方法,主要看对象左边的类型,和右边关系不大,Peraon类没有这个eat()的方法。
s2.eat();//报错
}
}
注意:
多态是方法的多态,属性没有多态。 父类和子类,两个类是有继承关系的,如没有继承关系则会出现类型转换异常的错误!ClassCastException!5.2 instanceof
instanceof 类型转换,引用类型转换,判断一个对象是什么类型~
instanceof 可以判断两个类是否存在继承关系。
public class Person {
}
public class Teacher extends Person {
}
public class Application {
public static void main(String[] args) {
//Object>String
//Object>Person>Teacher
//Object>Person>Student
Object object = new Student();
//System.out.println(X instanceof Y);//能不能编译通过,如果编译可以通过说明两个类有关系。
System.out.println(object instanceof Student);//显示结果turn
System.out.println(object instanceof Person);//显示结果turn
System.out.println(object instanceof Object);//显示结果turn
System.out.println(object instanceof Teacher);//显示结果false
System.out.println(object instanceof String);//显示结果false
System.out.println("=========");
Person person = new Student();
System.out.println(person instanceof Student);//显示结果turn
System.out.println(person instanceof Person);//显示结果turn
System.out.println(person instanceof Object);//显示结果turn
System.out.println(person instanceof Teacher);//显示结果false
//System.out.println(person instanceof String);//编译报错
System.out.println("=========");
Student student = new Student();
System.out.println(student instanceof Student);//显示结果turn
System.out.println(student instanceof Person);//显示结果turn
System.out.println(student instanceof Object);//显示结果turn
//System.out.println(student instanceof Teacher);//编译报错
//System.out.println(student instanceof String);//编译报错
}
}
5.3 类型转换
public class Person {
}
public class Teacher extends Person {
}
public class Application {
public static void main(String[] args) {
//类型之前转换:父类型是高的一方 子类型是低的一方
//类型从高到低是自动转换,从低到高需要强制转换。
Person obj = new Student();
//obj将这个对象转换为Student类型,我们就可以使用Student类型的方法了。
Student student=(Student) obj;
student.go();//直接可以写成((Student)obj).go();
Person person = student;
//父类强制转换为子类,可能丢失自己本来的一些方法!
//person.go()//报错没有这个方法。
}
}
5.4 static 关键字
静态属性
package com.oop.demo07;
//static
public class Student {
private static int age;//静态的变量 多线程!
private double score;//非静态的变量
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age);//类变量跟类中的所有实例共享
//System.out.println(Student.score);这是不行的
System.out.println(s1.age);
System.out.println(s1.score);
}
}
静态方法
package com.oop.demo07;
//static
public class Student {
private static int age;//静态的变量 多线程!
private double score;//非静态的变量
public void run(){//非静态方法可以调用静态方法里的所有东西
go();
}
public static void go(){//静态方法可以调用静态方法里的所有东西
}
public static void main(String[] args) {
new Student().run();//对象.方法
Student.go();
go();
}
}
静态代码块
package com.oop.demo07;
public class Person {
//2:赋初值~
{
//代码块(匿名代码块)
//没有名字,程序不会主动调用这些模块
//匿名代码块:创建对象时就自动创建了,而且在构造器之前
System.out.println("匿名代码块");
}
//1 : 只执行一次~
static {
//静态代码块
//可以在里面加载一些初始化的数据
//静态代码块:类一加载就直接执行,永久只执行一次
System.out.println("静态代码块");
}
//3
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("=================");
Person person2 = new Person();
}
}
package的一些新特性
package com.oop.demo07;
//静态导入包~
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
6.抽象类
abstract修饰符可以修饰方法也可以修饰类 抽象方法 抽象类 抽象类中可以没有抽象方法,抽象方法一定要声明为抽象类 抽象类不可以用new关键字来创建对象,它是用来让子类继承的 抽象方法,只有方法的声明,没有方法的实例,方法是让子类实现的 子类继承抽象类,必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
注:
抽象类中可以写普通方法
抽象方法必须在抽象类中
单继承(接口可以多继承)
public abstract class Action{
public abstract void doSomething();
}
抽象类:abstract extends
接口: interface implements
利用接口可以多继承
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范!自己无法写方法-专业约束!约束和实现分离,面向接口编程
接口就是规范
接口的本质就是契约
OO的精髓是对对象的抽象,最能体现这一点的就是接口
声明类的关键字是class,声明接口的关键字是interface
接口的作用:
1. 约束
2. 定义了一些方法、让不同的人实现
3. public abstract 声明方法修饰符
4. public static final 声明变量修饰符
5. 接口不可以实例化,接口中没有构造方法
6. implements可以实现多个接口
//接口都需要实现类
public interface UserService{
int age = 99; //常量 public static final
//接口中的所有定义的方法其实都是抽象的 public abstract
void add(String name);
void delete(String name);
}
//实现了接口的类,就需要重写接口中的方法
public class UserServiceIml implements UserService{
@Override
public void add(String name){
}
@Override
public void delete(String name){
}
}
8.内部类
public calss Outer{
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
public static class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//static 修饰的内部类,无法获取外部类的私有属性
public void getID(){
}
}
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//获取外部类的私有属性
public void getID(){
System.out.println(id);
}
}
public void method(){
//局部内部类
class Inner{
public void in(){
}
}
}
}
//一个java类中可以有多个class类,但是只能有一个public class
class A{
main()方法
public void eat(){
System.out.println("吃");
}
}
interface UserService{
void hello();
}
public class Application{
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.in();
//匿名内部类
new A().eat();
UserService userService = new UserService(){
@override
public void hello(){
}
};
}
}
9.异常处理机制
检查性异常:程序员无法预见的
运行时异常
错误
抛出异常捕获异常
异常处理的五个关键字
try catch finally throw throws
try 监控区域
catch 捕获异常
finally 善后异常
捕获异常从小到大
ctrl + alt + T
try{
抛出异常
if (b**0){
throw new ArithmeticException(); //主动抛出异常,一般在方法中使用
}
}catch(Exception e){
// catch只执行一个
e.printStackTrace(); //打印错误的栈信息
}catch(){
}finaly{
}
方法上抛出异常
public void test() throws Exception{
}
public class Test{
public static void main(String[] args){
int a = 1;
int b = 0;
try{ //监控区域
System.out.println(a / b);
}catch(Exception e) { //捕获异常 catch(需要捕获的异常类型)
System.out.println("程序异常");
}catch(Throwable e){
System.out.println("throwable");
}finally{ //无论有无异常都会执行,善后工作
System.out.println("finally");
}
}
}
自定义异常
用户自定义异常类,只需要继承Exception类即可
public class MyException throws Exception{
private int detail;
public MyException(int a){
this.detail = a;
}
@Override
public String toString(){
return "MyException{" + detail + "}";
}
}



