面向对象
- 面向过程&面向对象
- 面向过程:步骤清晰简单,第一步做什么,第二部做什么。。。
- 面向对象:分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索,面向对象适合处理复杂问题,适合处理需要多人协作的问题。
- 对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整合系统。但是具体到微观操作,仍然需要面向过程的思路去处理。
- 面向对象编程(Object-Oriented Programming,OOP)
- 本质:以类的方式组织代码,以对象的形式组织(封装)数据
- 核心思想:抽象
- 三大特性:
- 封装
- 继承
- 多态
方法回顾和加深
- 方法的定义
- return 结束方法,返回一个结果
- 修饰符
- 参数列表(参数类型,参数名)…
- 异常抛出:后面讲解
- 方法的调用:递归
-
静态方法:static关键字,有这个关键字的方法和类一起加载,而没有这个关键字,当类实例化之后才存在。
-
非静态方法
public class Demo1 { public void say(){ System.out.println("say what"); } public static void main(String[] args) { Demo1 student = new Demo1(); student.say(); } }
-
形参和实参
public class Demo2 { public static void main(String[] args) { int add = Demo2.add(1,2);//实参 System.out.println(add); } public static int add(int a,int b){//形参 return a + b; } }
-
值传递
public class Demo3 { public static void main(String[] args) { int a = 1; System.out.println(a); Demo3.change(1); System.out.println(a);//1 } public static void change(int a){ a = 10; } }
输出:
-
引用传递
public class Demo4 { public static void main(String[] args) { Student student = new Student(); System.out.println(student.name);//null Demo4.change(student); System.out.println(student.name);//hhh } public static void change(Student student){ student.name = "hhh"; } } class Student{ String name; }
输出:
-
对象的创建分析
- 类与对象的关系:类是一种抽象的数据类型,它是对某一类事物整体描述,如动物,手机等,而对象是抽象概念的具体实例,如狗,华为手机等
- 创建与初始化对象
-
使用new关键字创建对象(使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用)
无参构造必须显示定义,否则会报错,如下图所示:
无参构造必须显示定义,如下图所示:
生成有参构造器快捷键:ALT + insert键
生成无参构造器快捷键:ALT + insert键 选择无参即可
使用new关键字,本质是在调用构造方法,初始化对象的值
构造器:和类名相同 没有返回值 是public型
注意:定义有参构造之后,如果想用无参构造,需要显示的定义一个无参的构造内存分析:图来自狂神说Java
-
面向对象三大特性
- 封装
- 高内聚,低耦合 高内聚:类的内部数据操作细节自己完成;低耦合:仅暴露少量的方法给外部使用
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 增加系统可维护性
- 本质:属性私有,get/set方法访问属性
public class Demo6 { public static void main(String[] args) { Student_new student_new = new Student_new(); student_new.setName("hhhh"); student_new.getName(); } } class Student_new{ private String name; private int id; private char sex; //提供一些可以操作这个属性的方法 //get public String getName(){ return this.name; } public void setName(String name){ this.name = name; } }
- 继承
- 本质:对某一批类的抽象 关键字 extends,子类是父类的扩展
- Java中类只有单继承,没有多继承
- 继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖,组合,聚合等
- 继承关系的两个类,一个为子类,一个为父类 ctrl + H:展示类继承关系
- 子类和父类之间,从意义上讲,应该具有“is a”的关系,子类继承父类,就会拥有父类的全部方法,Java中,所有类直接或间接继承object类,私有内容无法被继承
- super
1). 先调用父类的构造器,必须要在子类构造器的第一行
2). super 必须只能出现在子类的方法或者构造方法中
3). super和this不能同时调用构造方法
与this的区别
1). 代表的对象不同 this:本身调用者这个对象 super:代表父类对象的应用
2). 前提:this 没有继承也可以使用 super只能在继承条件下才可以使用
3). 构造方法:this();本类的构造 super():父类的构造
输出:public class Main { public static void main(String[] args) { Student student = new Student(); student.test("hh"); student.test_1(); } } //子类继承父类,就会拥有父类的全部方法 //Java中,所有类直接或间接继承object类 //私有内容无法被继承 class Person{ protected String name = "hhh"; public Person() { System.out.println("Person 无参构造器执行"); } public void print(){ System.out.println("Person"); } } class Student extends Person{ //隐藏代码 //super(); //先调用父类的构造器,必须要在子类构造器的第一行 private String name = "h"; public Student() { System.out.println("Student 无参构造器执行"); } public void print(){ System.out.println("student"); } public void test(String name){ System.out.println(name); System.out.println(this.name); System.out.println(super.name); } public void test_1(){ print(); this.print();//当前类对象 super.print();//父类方法 } }
- 方法重写
1). 重写:需要继承关系,子类重写父类的方法
2). 注意:方法名必须相同,参数列表必须相同,修饰符:范围可以扩大但是不能缩小:public > protected >default > private 抛出异常:范围可以被缩小,但是不能扩大:classNotFoundException --> Exception(大)
3). 为什么需要重写:父类的功能子类不一定需要,或者不一定满足!快捷键“ Alt + Insert 选Override
输出:public class Demo1 { //静态方法和非静态方法有区别 //非静态方法重写 public static void main(String[] args) { //静态方法的调用只和左边定义的数据类型有关 A a = new A(); a.test(); //父类的引用指向了子类 B b = new A(); b.test(); } } class B{ public void test(){ System.out.println("B test"); } } class A extends B { public void test(){ System.out.println("A test"); } }
- 多态
- 可以实现动态编译,增强可扩展性
- 注意事项:1)多态是方法的多态,属性没有多态 2)父类和子类,有联系,否则类型转换异常 !ClassCastException 3)多态存在条件:继承关系,需要有方法重写,父类的对象指向子类的对象。
- 不能有多态的: 1)static 方法,属于类,不属于实例 2)final 常量 3)private方法
public class Demo1 { public static void main(String[] args) { //一个对象的实际类型是确定的,如new了一个Student对象,则这个对象是属于Student的 new Student(); //但是这个对象指向的引用类型不确定:父类的引用指向子类 //Student 能调用的方法都是自己的或者继承父类的 Student student1 = new Student(); //Person 父类型,可以指向子类,但是不能调用子类独有的方法 Person student2 = new Student(); Object student3 = new Student(); student2.run(); student1.run(); //对象能执行哪些方法,主要看对象左边的类型, student2.eat(); } } class Person{ public void run(){ System.out.println("run"); } } class Student extends Person{ public void run(){ System.out.println("son"); } public void eat(){ System.out.println("eat"); } }
- instanceof (类型转换)引用类型 判断一个对象的类型
1) 注意使用该关键字需要两个之间有关系 X instanceof Y,重点是判断对象类型是根据new关键字确定的
输出:public class Demo2 { public static void main(String[] args) { Object object = new Person1(); Person1 person1 = new Student1(); Person1 person2 = new Teacher(); System.out.println(person1 instanceof Teacher); System.out.println(person1 instanceof Person1); System.out.println(person1 instanceof Student1); System.out.println(); System.out.println(person2 instanceof Teacher); System.out.println(person2 instanceof Person1); System.out.println(person2 instanceof Student1); } } class Person1{ } class Teacher extends Person1{ } class Student1 extends Person1{ }
2) 类型转换public class Demo3 { public static void main(String[] args) { //高 -----低 A b = new B(); B c = (B) b; //多态存在条件:父类引用指向子类的对象 //把子类转换为父类,向上转型; //把父类转换为子类,向下转型,强制转换 //方便方法调用,减少重复代码,核心思想:简洁 } } class A{ } class B extends A{ }
static
- 静态代码块,主要赋初值,只加载一次
输出:public class Demo4 { public static void main(String[] args) { S_test sTest = new S_test(); } } class S_test{ { System.out.println("匿名代码块"); } static { System.out.println("静态代码块"); } public S_test() { System.out.println("构造方法"); } }
- 使用final关键字的类不能被继承
//静态导入包 import static java.lang.Math.random; import static java.lang.Math.PI; public class Demo5 { public static void main(String[] args) { System.out.println(random()); System.out.println(PI); } } //final关键字的类,不能被继承 final class C{ } class D extends C{ }
抽象类和接口
- abstract类修饰
- 不能new抽象类,只能靠子类去实现它,约束
抽象方法必须在抽象类中
抽象类中可以有普通的方法
- 接口
- 普通类:只有具体实现 抽象类: 具体实现和抽象方法都有
- 接口:只有规范
- 接口就是规范,定义的是一组规范
- OO的精髓:是对对象的抽象,最能体现这一点的就是接口
- 作用:1. 定义一些方法,让不同的人实现 2. 方法都是public abstract ,常量都是public static final 3. 接口不能被实例化,接口中没有构造方法 4.implements可以实现多个接口,但是必须要重写接口
内部类及OOP实战
- 内部类:就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对于A类来说就称为内部类,A类相对于B类来说就是外部类了。
- 成员内部类:
class Outer{ private int id = 10; public void out(){ System.out.println("Outer method"); } class Inner{ public void in(){ System.out.println("Inner method"); } public void getID(){ System.out.println(id); } } }
- 静态内部类:给内部类加static关键字
- 局部内部类:
class A{ public void method(){ class Inn{ public void hhh(){ } } } }
- 匿名内部类
- 完整代码
输出:public class Demo1 { public static void main(String[] args) { Outer outer = new Outer(); //没有名字初始化类,不用将实例保存到变量中 new Outer().out(); //通过外部类来实例化内部类,可以获得外部类的私有属性 Outer.Inner inner = outer.new Inner(); inner.in(); inner.getID(); } } class Outer{ private int id = 10; public void out(){ System.out.println("Outer method"); } class Inner{ public void in(){ System.out.println("Inner method"); } public void getID(){ System.out.println(id); } } } class A{ public void method(){ class Inn{ public void hhh(){ } } } }
异常
-
异常定义
- 程序运行中出现的不期而至的各自状况,如:文件找不到、网络连接失败、非法参数等
- 检查性异常:用户错误或问题引起的异常,这是程序员无法预见的。eg:要打开一个不存在的文件时,一个异常就发生了,这些异常在编译时不能被简单的忽略。
- 运行时异常:运行时异常是可能被程序员避免的异常
- 错误error:错误不是异常,而是脱离程序员控制的问题。错误在代码中常被忽略
-
异常体系结构
- Java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
- 异常分为两大类:错误error和异常exception
- Error: Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
1)Java虚拟机运行错误(Virtual MachineError):当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择终止线程;
2)还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为他们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的情况。 - Exception:
1)RuntimeException:ArrayIndexOutOfBoundsException; NullPointException; ArithmetricException; MissingResourceException; ClassNotFoundException等,这些异常是不检查异常,程序中可以捕获处理,也可以不处理。
以下图来自狂神
-
Java异常处理机制
抛出异常,捕获异常
异常处理五个关键字:try catch finally throw throws-
try catch finally
public class Demo1 { public static void main(String[] args) { int a = 1; int b = 0; //捕获多个异常,从小到大 try { //监控区域 System.out.println(a / b); }catch (ArithmeticException e){ //捕获异常 System.out.println("Exception,b不能等于 0"); }catch (Error e){ //捕获异常 System.out.println("Exception 循环调用"); } finally { //善后,可以不要 System.out.println("finally"); } } public void a(){ b(); } public void b(){ a(); } }
输出:
-
主动抛出异常,throw
和上面代码一样,输出:
或者主动抛出异常 throwimport outer_Class.Demo1; public class Demo2 { public static void main(String[] args) { new Demo2().test(1,0); } public void test(int a,int b){ if (b == 0){ throw new ArithmeticException();//主动抛出异常,一般在方法中使用 } System.out.println(a / b); } }
输出:
-
主动抛出异常,throws
import outer_Class.Demo1; public class Demo2 { public static void main(String[] args) { try { new Demo2().test(1,0); }catch (ArithmeticException e){ System.out.println("hhh"); // e.printStackTrace(); } } public void test(int a,int b) throws ArithmeticException{ if (b == 0){ throw new ArithmeticException();//主动抛出异常,一般在方法中使用 } System.out.println(a / b); } }
注意:在方法名字那里主动抛出异常,使用throws关键字,要用try-catch捕获
输出:
-
-
自定义异常
- 用户定义异常,只需要继承Exception类即可
- 自定义异常类步骤:1)创建自定义类;2)在方法中通过throw关键字抛出异常;3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步的操作;4)在出现异常方法的调用者中捕获并处理异常。
输出:public class Demo3 { public static void main(String[] args) { try { Demo3.test(1); }catch (MyException e){ System.out.println("My Exception :" + e); } } static void test(int a) throws MyException{ System.out.println("传递的参数为:" + a); if (a > 10){ throw new MyException(a); } System.out.println("OK"); } } class MyException extends Exception{ private int detail; public MyException(int a) { this.detail = a; } @Override public String toString() { return "MyException{" + "detail=" + detail + '}'; } }
当传递参数为10时,则抛出异常:
-
总结
- 处理运行时异常时,采用逻辑去合理规避同时辅助使用try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能被遗漏的异常
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量去处理异常,切忌只是简单调用printStackTrace()去打印输出
- 尽量添加finally语句块去释放占用的资源
- 快捷键:Alter+ ctrl键