简单小结类和对象
package com.hashiqi.oop;
public class Application {
public static void main(String[] args) {
--------------------------------------------------
1.类与对象
类是一个模板:抽象,对象是一个具体的实例
2.方法
定义、调用!
3.对应的引用
引用类型: 除基本类型(8)
对象是通过引用来操作的:栈 -->堆
4.属性: 字段Field 成员变量
默认初始化:
数字: 0 0.0
char: u0000
boolean: false
引用: null
修饰符 属性类型 属性名 = 属性值 ;
5.对象的创建和使用
- 必须使用new关键字创造对象,构造器 Pet dog = new Pet();
- 对象的属性 dog.name
- 对象的方法 dog.sleep()
6.类:
静态的属性 属性
动态的行为 方法
java面向对象三大特征
封装、继承、多态
--------------------------------------------------
}
}
封装
该露的露,该藏的藏
- 程序设计追求"高内聚、低耦合"。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
记住这句话就够了: 属性私有, get/set
package com.hashiqi.oop.demo04;
public class Student {
//属性私有
//名字
private String name;
//学号
private int id;
//性别
private char sex;
//年龄
private int age;
//提供一些可以操作这个属性的方法!
//提供一些public的get 和set的方法
//get 获得这个数据
public String getName(){
// return this.name;
return name;
}
//set 给这个数据设置值
public void setName(String name){
this.name = name;
}
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;
}
}
}
package com.hashiqi.oop;
import com.hashiqi.oop.demo04.Student;
/*
1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.统一接口
4.系统可维护增加了
*/
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("二哈");
System.out.println(s1.getName());
s1.setId(35);
System.out.println(s1.getId());
s1.setAge(70);
System.out.println(s1.getAge());
}
}
重载
方法 一样,则方法名一致,方法名一致,参数列表又相同,则是同一个方法
继承
-
继承本质是对某一批类的抽象,从而实现对显示世界更好的建模。
-
extends的意思是“扩展”、子类是父类的扩展。
-
JAVA中类只有单继承,没有多继承!
-
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
-
继承关系的是两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
-
子类和父类之间,从意义上讲应该具有“is a"的关系。
-
object类
-
super-this
-
方法重写
语法:
public class XXX expends XXX{
}
例如:
public class Student expends Person{
}
object
package com.hashiqi.oop.demo05;
//在Java中,所有的类,都默认直接或间接继承object
//Person 人 作为Teacher Student 的父类
public class Person {
private int money = 10_0000_0000;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void say(){
System.out.println("说了一句话");
}
}
package com.hashiqi.oop;
import com.hashiqi.oop.demo05.Student;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
System.out.println(student.getMoney());
}
}
小结:
在Java中,所有的类都有一个父类object,默认直接或间接继承object
super-this
1.super调用父类的构造方法,必须在构造方法的第一个
2.super必须只能出现在子类的方法或者构造方法中!
3.super和this不能同时调用构造方法!
VS this:
代表的对象不同:
this :本身调用者这个对象
super:代表父类对象的应用
前提
this:没有继承也可以使用
super:只能在继承条件下才可以使用
构造方法
this()本身的构造
super();父类的构造!
//Student.java 子类
package com.hashiqi.oop.demo05;
//学生 is 人的:派生类,子类
//子类继承了父类,就会又父类的全部方法;
public class Student extends Person {
public String name = "erha";
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(){
print();
this.print();
super.name();
*/
//Person.java 父类
package com.hashiqi.oop.demo05;
//在Java中,所有的类,都默认直接或间接继承object
//Person 人 作为Teacher Student 的父类
public class Person {
protected String name = "hashiqi";
}
//调用对象
package com.hashiqi.oop;
import com.hashiqi.oop.demo05.Student;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("哈士奇");
}
}
方法重写:
重点—>多态
重写:需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表列表必须相同
- 修饰符:范围可以扩大但不能缩小: public>protected>default>private
- 抛出的异常:范围,可以被缩小,但不能扩大:ClassNotFoundException --> Exception(大) (错误)
重写,子类的方法和父类必须一致:方法体不同
为什么需要重写:
- 父类的功能,子类不一定需要
- 父类的功能,不满足子类的需求
- Alt +Insert :override;
静态方法
//父类
package com.hashiqi.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
---------------------------------------------------------
//子类
package com.hashiqi.oop.demo05;
public class A extends B{
//override 重写
@Override //注释:有功能的注释!
public static void test() {
System.out.println("A=>test()");
}
}
---------------------------------------------------------
package com.hashiqi.oop;
import com.hashiqi.oop.demo05.A;
import com.hashiqi.oop.demo05.B;
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()
}
}
非静态方法:
//父类
package com.hashiqi.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
---------------------------------------------------------
//子类
package com.hashiqi.oop.demo05;
public class A extends B{
//override 重写
@Override //注释:有功能的注释!
public void test() {
System.out.println("A=>test()");
}
}
---------------------------------------------------------
//主程序
package com.hashiqi.oop;
import com.hashiqi.oop.demo05.A;
import com.hashiqi.oop.demo05.B;
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()
}
}
静态的方法和非静态的方法区别很大!
静态方法:方法的调用之和左边,定义的数据类型有关
非静态方法:重写
多态
定义:
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)
多态存在的条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
instanceof (类型转换) 引用类型
-
子类可以调用自己的方法或者继承父类的
-
父类可以指向子类,但不能调用子类独有的方法
-
若要调用,要么在父类写相同的方法,由子类重写
-
要么调用的时候强制转换类型(高转低),例如:
Person是父类,Student是子类,Student有eat方法,Person没有
((Student) s2).eat();
-
-
对象能执行哪些方法,主要看对象左边的类型,和右边关系不大!
多态的注意事项:
- 多态是方法的多态,属性没有多态性。
- 父类和子类,有联系, 类型转换异常! ClassCastException!
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
- 以下无法被重写
- 1.static 方法,属于类,它不属于实例;
- 2.final 常量;
- 3.private 方法;
//Person 父类
package com.hashiqi.oop.demo06;
public class Person {
public Object eat;
public void run(){
System.out.println("run");
}
}
--------------------------------------------------------
//Student 子类
package com.hashiqi.oop.demo06;
public class Student extends Person{
public void run(){
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
--------------------------------------------------------
//Teacher 子类
package com.hashiqi.oop.demo06;
public class Teacher extends Person{
}
--------------------------------------------------------
//主程序
package com.hashiqi.oop;
import com.hashiqi.oop.demo06.Person;
import com.hashiqi.oop.demo06.Student;
import com.hashiqi.oop.demo06.Teacher;
public class Application {
public static void main(String[] args) {
//Object> String
//Object> Person>Student
//Object> Person>Teacher
Object object = new Student();
//System.out.println(X instanceof Y);能不能编译通过,取决于X与Y是否存在父子关系
//new 的对象与关键字的右边判断是否有关系
System.out.println(object instanceof Student);//ture
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//ture
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);//ture
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//ture
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);//ture
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//ture
//System.out.println(student instanceof Teacher);//编译报错
//System.out.println(student instanceof String);//编译报错
}
}
instanceof和类型转换:
父类使用子类特有方法
Person s1 = new Student();
student.go;
//等价于
((Student)s1).go;
子类转换为父类
缺点:转换之后无法使用子类特有方法
Person s2 = new Student();
注意:
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型;
- 把父类转换为 子类,向下转型,强制转换
- 方便方法的调用,减少重复的代码,简介
面向对象的三大特征
抽象:编程思想,需要持续学习,多实践,测试自己的想法,实践出真知
封装、继承、多态
Static关键字详解
静态变量在类进行初始化时候便分配了内存。
普通变量只有类进行实例化的时候进行内存分配。
package com.hashiqi.oop.demo07;
//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 s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println(s1.score);
}
}
静态方法,非静态方法的互相调用
①静态方法可以互相调用,mian也是静态方法
public static void main(String args[]){}
例如:
public static void go(){
System.out.println("go");
}
public static void main(String args[]){
Student.go();//go
}
或者
public static void go(){
System.out.println("go");
}
public static void main(String args[]){
go();//go
}
②非静态方法,可以调用静态方法的所有东西
public class Student(){
public static void go(){
}
--------------------------------------------
public void run(){
go();
}
--------------------------------------------
public static void main(String args[]){
}
}
③静态方法,可以调用静态方法的,但无法调用非静态方法,因为类加载(初始化)的时候未给非静态的成员变量分配内存空间
-
main也是一个静态方法,psvm
-
原因是:类的加载顺序问题,静态区跟类一块加载
public calss Student(){
public void run(){
}
public static void go(){
}
public static void main (String args[]){
run(); //编译错误
}
}
如果想调用非静态方法
需要先进行实例化,new一个对象,才可以引用非静态方法
public calss Student(){
public void run(){
}
----------------------------------------------
public static void go(){
}
----------------------------------------------
public static void main (String args[]){
new Student().run();
}
}
代码块
(1)匿名代码块,程序在执行的时候不能主动调用,在对象创建的时候自动创建了,在构造器之前
(2)静态代码块,跟随类的加载直接执行,永久只执行一次
public class Person {
{
//匿名代码块
}
static{
//静态代码块
}
}
package com.hashiqi.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();
}
}
//输出(顺序)如下
静态代码块
匿名代码块
构造方法
=====================
匿名代码块
构造方法
若是想导入某个类里面的方法,又不想输入方法的前缀(导入的方法的类)
如Math.random() 省略掉Math, 直接使用random();
package com.hashiqi.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);
}
}
如果类用final (常量)修饰,则无法被继承
例如:
public final class Person(){}
public class Student extends Person(){
}
//错误,显示无法继承
参考链接:https://zhuanlan.zhihu.com/p/131304193
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类.
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
- 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
- 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
- 子类继承抽象类,那么就必须要实现抽象类没有实现实现的抽象方法,否则该类也要声明为抽象类。
抽象类里构造器的作用
- 子类继承抽象类时,构造函数不会被覆盖。
- 而且,在实例化子类对象时首先调用的是抽象类中的构造函数再调用子类中的。
- 在调用父类(抽象类)中的构造函数也可以对父类中的成员变量进行初始化赋值!
接口
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)都有!
-
接口:只有规范!
-
接口就规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
-
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
-
OO的精髓,是对对象的抽象,最能体现着一点的就是接口。为什么我讨论设计模式都只针对具备了抽象能力的语言(比如C++、java+、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
声明类的关键字是class,声明接口的关键字是interface
/*UserService.java*/
package com.hashiqi.oop.demo09;
public interface UserService {
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
/*TimeService*/
package com.hashiqi.oop.demo09;
public interface TimeService {
void Timer();
}
/*UserServiceImpl.java*/
package com.hashiqi.oop.demo09;
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() {
}
}
作用:
- 约束
- 定义一些方法,让不同的人实现
- public abstract
- public static final
- 接口不能被实例化,因为接口中没有构造方法
- Implements可以实现多个接口
- 必须重写接口中的方法
内部类
-
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
-
1.成员内部类
-
2.静态内部类
-
3.局部内部类
-
4.匿名内部类
/*Outer.java*/
package com.hashiqi.oop.demo10;
public class Outer {
private static int id=10;
public void out(){
System.out.println("这是外部类方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类方法");
}
//获取外部私有属性
public void getID(){
System.out.println(id);
}
}
}
/*Application.java*/
package com.hashiqi.oop;
import com.hashiqi.oop.demo10.Outer;
public class Application {
public static void main(String[] args) {
Outer s1 = new Outer();
Outer.Inner s2 = s1.new Inner();
s2.getID();
}
}
注意点:一个java类中,可以有多个class类,但是只能有一个public class
package com.hashiqi.oop.demo10;
public class Test {
public static void main(String[] args) {
}
}
class A{
public static void main(String[] args) {
}
}
局部内部类
package com.hashiqi.oop.demo10;
public class Test {
public void method(){
//局部内部类
class A{
public void in(){
}
}
}
}
匿名类
package com.hashiqi.oop.demo10;
public class Test1 {
public static void main(String[] args) {
//没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
//new接口的实现类
new UserService(){
@Override
public void Hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserService{
void Hello();
}
异常
-
实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等等。我们的程序在跑着,内存或硬盘可能满了,等等。
-
软件程序在运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是:Exception,意思是例外。这些,例外情况,或者叫异常,这么让我们写的程序作出合理的处理。而不至于程序崩溃。
-
异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
-
异常发生在程序运行期间,它影响了正常的程序执行流程。
简单分类
-
要理解Java异常处理是如何工作的,你需要掌握以下三个类型的异常:
-
异常处理框架
-
检查性异常:最具党代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个个不存在文件时,一个异常就发生了,这些异常咋洗编译时不能被简单地忽略。
-
运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在被编译时被忽略。
-
错误ERROR:错误吧是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如:当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
异常体系结构
java把异常当作对象来处理,并定义了一个基类java.lang.Throwable作为所有异常的超类。
在java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7zdNhzc-1593957698286)(异常体系结构.png)]
Error
- Error类对象由于Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
- Java 虚拟机运行错误(VirTUAL MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemorvError,这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
Exception
-
在Exception分支中有一个重要的子类RuntimeException(运行时异常)
- ArrayIndexOutOfBoundsException(数组下标越界)
- NullPointerException(空指针异常)
- ArithmeticException(算数异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中科院选择捕获处理,也可以不处理
-
这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;
-
Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
package com.exception; public class Test { public static void main(String[] args) { int a = 1; int b = 0; try {//try监控区域 System.out.println(a / b); } catch (ArithmeticException e) {//catch(想要捕获的异常类型)捕获异常 System.out.println("程序出现异常,分母不能为零"); } finally {//处理善后工作 System.out.println("finally"); } //finally可以不要finally 一般用于IO,资源关闭 } public void a(){ b(); } public void b(){ a(); } }
可以捕获多个异常,层层递进,从小到大,范围最大的放底层
package com.exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {//try监控区域
System.out.println(a / b);
} catch (Error e) {
System.out.println("Error");
} catch (Exception e) {
System.out.println("Exception");
}catch (Throwable e) {
System.out.println("Throwable");
}
finally {//处理善后工作
System.out.println("finally");
}
//finally可以不要finally 一般用于IO,资源关闭
}
public void a(){
b();
}
public void b(){
a();
}
}
异常处理机制
-
抛出异常
-
捕获异常
-
异常处理五个关键字
- try、catch、finally、throw、throws
主动抛出异常
package com.exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {//try监控区域
new Test().test(1,0);
}catch(ArithmeticException e){
e.printStackTrace();
}
}
public void test(int a ,int b){
if (b == 0) {//主动抛出异常 throw throws
throw new ArithmeticException();//主动的抛出异常
}
}
}
自定义异常
- 使用java内置的异常类可以描述在编程时初夏你的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
- 在程序中使用自定义异常类,大体可分为以下接步骤:
- 创建自定义异常类
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throw是关键字知名要抛出给方法调用者的异常,继续进行下一步操作。
- 在出现异常方法的调用者中捕获并处理异常
实际用中的经验总结
- 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量处理异常,切忌只是简单的调用printStackTrace()去打印输出
- 具体如何处理异常,要根据不同的业务需要和异常类型去决定
- 尽量添加finally语句块去释放占用的资源(IO ~ Scanner ~)