Java面向对象
Object-Oriented Programming , 本质 : 以类的方式组织代码 , 以对象的组织(封装)数据
抽象
三大特性----封装 , 继承 , 多态
类与对象
类是抽象的,使用new创建对象
public class Application {
public static void main(String[] args) {
Student student=new Student();
System.out.println(student.name);
student.name="老王";
System.out.println(student.name);
}
}
======
public class Student {
//属性 : 字段
String name;
int age;
//方法 只存在这两个东西
public void study(){
System.out.println(this.name+"在学习哦");
}
}
构造器
一个类即使什么都不写,也有个默认的构造器
-
使用new关键字,本质是在调用构造器
-
一旦定义了有参构造,无参就必须显示定义
-
实例化初始值
IDEA快捷键 : alt+insert
public class Person {
String name;
int age;
public Person(){
this.name = "老王";
}
public Person(String name){
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/*
1. 和类名相同
2. 没有返回值
作用 :
1. new 本质实在调用构造方法
2. 初始化对象的值
注意 :
* 定义了有参之后,如果想使用无参,必须要显式定义无参
*/
}
======
public class Application {
public static void main(String[] args) {
//new实例化了一个对象
Person person=new Person();
System.out.println(person.name);
}
}
内存对象分析
栈中加载方法 , 堆中有一块方法区
首先在栈中加载main()方法 , Cat c=new Cat(); , 栈中存放的是引用变量名,指向堆中的地址 , 对象是通过引用来操作的 ( 栈—>堆 )
public class Application {
public static void main(String[] args) {
Cat c=new Cat();
c.name="咪咪";
c.age=3;
c.run();
Cat b=new Cat();
}
}
============
public class Cat {
public String name;
public int age;
public void run(){
System.out.println("猫猫跑了.");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cN5z7z8F-1638108154458)(C:\Users\Yu\Desktop\内存图.png)]
封装
数据的隐藏 , 该露的露 , 该藏的藏----->高内聚 , 低耦合
高内聚 : 类的内部数据操作细节自己完成 , 不允许外部干涉
低耦合 : 仅暴露少量的方法给外部使用
一句话 : 属性私有 , get/set
get : 获得这个数据
set : 给这个数据设置值
alt+insert快捷键
**意义 : **
- 提高程序的安全性 , 保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护性增加了
public class Application {
public static void main(String[] args) {
Student s1=new Student();
s1.getName();
s1.setAge(150);
}
}
==========
public class Student {
private String name; //姓名
private int age; //年龄
private String sex; //性别
//提供get/set方法
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(this.age<=0 || this.age>120){
System.out.println("不合法");
}else{
this.age = age;
}
}
}
重载
参照 : System.out.println(); //能输出很多东西
构造器用的重载较多
方法名相同 , 参数列表不同
继承
extends 子类是父类的扩展
继承是类和类 , 还有依赖 , 组合 , 聚合等
子类(派生类)----父类(积累)
子类继承父类 , 就会拥有父类的全部方法,属性 (非私有的)
ctrl+H快捷键打开继承树关系
所有的类都默认直接或者间接继承Object类
Java中只有单继承 , 没有多继承
super
super关键点 :
- super调用父类的构造方法,必须在构造方法的第一个。
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
super & this :
代表的对象不同 :
- this:本身调用这个对象
- super:代表父类对象的引用
前提:
- this:没有继承也可以使用
- 只能在继承条件才可以使用
构造方法:
- this():本类的构造
- super():父类的构造
public class Application {
public static void main(String[] args) {
Teacher teacher=new Teacher();
teacher.output("软件工程");
}
}
=======
public class Person {
public String name;
public String dept="计算机学院";
public Person(String name){
this.name=name;
}
public Person(){} //如果没有无参的构造方法则会报错,因为没有了默认的构造方法
}
=======
public class Teacher extends Person{
public int age;
public String dept="计算机科学与技术";
public Teacher(String name,int age){
super(name);
this.age=age;
}
public Teacher(){}
public void output(String dept){
System.out.println("super.dept = " + super.dept);
System.out.println("this.dept = " + this.dept);
System.out.println("dept = " + dept);
}
}
方法重写
重写都是方法的重写
前提 : 需要有继承关系 , 子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符 : 范围可以扩大 , 但是不能缩小
- 抛出的异常 : 范围可以被缩小 , 但不能扩大
----方法名相同 , 方法体不同
为什么需要重写 ?
–父类的功能子类不一定需要或者不满足
public class Application {
public static void main(String[] args) {
Son s=new Son();
s.test();
Father f=new Son();
f.test();
}
}
=========
public class Father {
public void test(){
System.out.println("我是father");
}
}
=========
public class Son extends Father{
@Override
public void test() {
System.out.println("我是son");
}
}
多态
一个对象的实际类型是确定的 , 可以指向的引用类型就不确定了 : 父类的引用指向子类
多态注意事项:
- 多态是方法的多态
- 父类和子类有联系 , 否则类型转换异常 : ClassCastException!
- 存在条件 : 继承关系–方法重写–父类引用指向子类对象
无法重写 :
- static方法 , 属于类 , 不属于实例
- final 常量
- private方法
public class Application {
public static void main(String[] args) {
//s1调用的方法是Student独有的或者是继承父类的
Student s1=new Student();
//s2 左边编译 , 右边执行 , 不能调用子类独有的方法
Person s2=new Student();
Object s3=new Student();
s2.eat();
}
}
============
public class Person {
public void eat(){
System.out.println("father eat");
}
}
============
public class Student extends Person{
@Override
public void eat() {
System.out.println("son eat");
}
}
instanceof
判断是否存在父子关系
理清关系即可
// Object > Person > Student
// Object > Person > Teacher
// Object > String
Object s1=new Student();
Student s2=new Student();
boolean b1=s1 instanceof Object;
boolean b2=s1 instanceof Person;
System.out.println(b1+" "+b2);
boolean b3=s1 instanceof String;
System.out.println(b3);
System.out.println("===============");
Person p=new Student();
boolean p1=p instanceof Person;
boolean p2=p instanceof Object;
System.out.println(p1+" "+p2);
true true
false
===============
true true
类型转换
- 父类引用指向子类的对象
- 把子类转换为父类 : 向上转型
- 把父类转换为子类 : 向下转型—强制转换
- 方便方法的调用 , 减少代码的重复
public class Application {
public static void main(String[] args) {
//高 低
//将 obj 转换为 Student 类型 , 就能使用 Student 独有的方法
Person obj = new Student();
//obj.sleep();
Student student=(Student)obj;
student.sleep();
student.eat();
//想要用子类的方法 , 把它强转为子类就行了
((Student)obj).sleep();
Person person=student;
//子类转换为父类 , 可能会丢失自己的方法
//person.sleep();
}
}
============
public class Person {
public void eat(){
System.out.println("father eat");
}
}
============
public class Student extends Person{
@Override
public void eat() {
System.out.println("son eat");
}
public void sleep(){
System.out.println("Student sleep");
}
}
static关键字
public class Student extends Person{
{ //赋初始值
//匿名代码块 , 构造器之前 , 不能主动调用
System.out.println("我是son匿名");
// --2
}
static{
//静态代码块 , 加载初始化数据
//类一加载就执行 , 只执行一次
System.out.println("我是son static");
// --1
}
public Student(){
System.out.println("我是son构造");
// --3
}
}
===============
public class Person {
{
System.out.println("我是father匿名");
}
static{
System.out.println("我是father static");
}
public Person(){
System.out.println("我是father构造");
}
}
===============
public class Application {
public static void sleep(){
}
public void run(){
sleep(); //非静态方法能调用静态方法或非静态
}
public static void main(String[] args) {
// run(); static static方法只能调用static修饰的方法或变量
sleep();
Student s1=new Student();
System.out.println("------------");
Student s2=new Student();
System.out.println("------------");
System.out.println(random());
System.out.println(PI);
}
}
扩展 :
静态导入包
import static java.lang.Math.random;import static java.lang.Math.PI;System.out.println(random());System.out.println(PI);
顺序⭐⭐⭐⭐⭐⭐:
我是father static
我是son static
我是father匿名
我是father构造
我是son匿名
我是son构造
父类static块>子类static块>父类匿名块>父类构造>子类匿名块>子类构造
抽象类
- 不能new出实例 , 只能靠子类去实现它 , 约束
- 抽象类可以写普通方法 , 抽象类可以有构造器
- 抽象方法必须在抽象类中
public abstract class Animal {
//所有的抽象方法在子类中都要重写,除非~
public abstract void run();
public Animal(){
System.out.println("我存在");
}
}
==============
public class Dog extends Animal{
//如果子类也是抽象的 , 则可以不用重写父类的抽象方法
@Override
public void run() {
}
}
接口
面向接口编程
接口就是一种规范 , 定义的是一组规则
接口作用:
- 一个约束
- 定义一些方法 , 让不同的人实现
- 方法都是 public abstract
- 变量都是 public static final
- 接口不能被实例化 , 接口没有构造方法
- 接口可以实现多个
- 实现接口必须要重写接口的方法
内部类
一个类中定义一个类
- 成员内部类
public class Application {
public static void main(String[] args) {
Outer outer=new Outer();
//Outer.Inner inner=new Outer().new Inner();
Outer.Inner inner=outer.new Inner();
System.out.println(inner.getAge());
inner.inner();
}
}
===============
public class Outer {
private int age=20;
public void outer(){
System.out.println("我是外部类");
}
public class Inner{
public void inner(){
outer();
System.out.println("我是内部类");
}
public int getAge(){
return age;
}
}
}
- 静态内部类
public class Outer {
private int age=20;
public void outer(){
System.out.println("我是外部类");
}
public static class Inner{
public void inner(){
System.out.println("我是内部类");
}
}
}
- 局部内部类
public class Application {
public static void main(String[] args) {
class Inner{
public void inner(){
System.out.println("局部内部类");
}
}
}
}
- 匿名内部类
public class Application {
public static void main(String[] args) {
new Apple().eat();
}
}
class Apple{
void eat(){}
}