面向对象
面向过程和面向对象的理解:
用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。所谓盖浇饭,北京叫盖饭,东北叫烩饭,广东叫碟头饭,就是在一碗白米饭上面浇上一份盖菜,你喜欢什么菜,你就浇上什么菜。我觉得这个比喻还是比较贴切的。
蛋炒饭制作的细节,我不太清楚,因为我没当过厨师,也不会做饭,但最后的一道工序肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢,则是把米饭和盖菜分别做好,你如果要一份红烧肉盖饭呢,就给你浇一份红烧肉;如果要一份青椒土豆盖浇饭,就给浇一份青椒土豆丝。
蛋炒饭的好处就是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。
到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。如果大家都不是美食家,没那么多讲究,那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。
盖浇饭的好处就是”菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是”可维护性“比较好,”饭” 和”菜”的耦合度比较低。蛋炒饭将”蛋”“饭”搅和在一起,想换”蛋”“饭”中任何一种都很困难,耦合度很高,以至于”可维护性”比较差。软件工程追求的目标之一就是可维护性,可维护性主要表现在3个方面:可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。
面向对象的本质
以类的方式组织代码,以对象的方式组织(封装)数据。
抽象:
把很多同样的东西抽取出来放在一起。
对象 是具体的事物。
类 是抽象的,对对象的抽象。
三大特性
封装 继承 多态
调用方法:
public static void main(String[] args) {
//调用静态方法
demo03.asd();
//调用非静态方法 先实例化这个类
demo01 demo01 = new demo01();
demo01.aad();
}
static 是和类一块加载的,非静态方法是类实例化之后才存在的。
构造方法
定义
类中的构造器也称为构造方法,是在进行创建对象的时候必须调用,并且构造器有以下两个特点:
1 必须和类名相同;
2必须没有返回类型,也不能写void;
作用:
1、使用new关键字本质是在调用构造器(通过new去走构造器)
2、初始化值
注意点
定义了有参构造,如果想使用无参构造,必须显示的定义无参构造
public class Dog {
String name;
int age;
public static void play(){
System.out.println("玩耍");
}
//无参构造器
public Dog() {
}
//有参构造器
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
封装
高内聚,低耦合
高内聚 就是类的11内部数据操作细节自己完成,不允许外部干涉
低耦合 仅暴露少量的方法给外部使用
属性私有,get/set
public class Dog01 {
//属性私有
private String name;
private int age;
//get、set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
Dog01 dog01 = new Dog01();
dog01.setName("多多");
dog01.setAge(1);
System.out.println(dog01.getName());
System.out.println(dog01.getAge)
}
继承
继承就是扩展,子类对父类的扩展。
super this注意点
-
super调用父类的构造方法,必须在构造方法的第一个
-
super 必须只能出现在子类的方法或者构造方法中
-
super和this不能同时调用构造方法
VS this
代表的对象不同
this:本身调用者这个对象
super 代表父类对象的应用
前提:
this没有继承也可以使用
super只有在继承条件下使用
构造方法
this() 调用本类的构造
super()调用父类的构造
方法重写
静态方法(不能被重写)
classA
public class A extends B{
public static void test(){
System.out.println("A=>test");
}
}
classB
public class B {
public static void test(){
System.out.println("B=>test");
}
}
C
public class demo01 {
public static void main(String[] args) {
A a = new A();
a.test();
//父类的引用指向子类
B b = new A() ;
b.test();
}
}
输出结果是:
A=>test
B=>test
非静态方法
classA
public class A extends B{
classB
public class B {
public static void test(){
System.out.println("B=>test");
}
}
C
public class demo01 {
public static void main(String[] args) {
A a = new A();
a.test();
//父类的引用指向子类
B b = new A() ;
b.test();
}
}
输出结果是:
A=>test
A=>test
总结:
即b是A new出来的对象,因此调用了A的方法,因为静态方法是类的方法,而非静态方法是对象的方法,有static时,b调用了B类的方法,因为b是用b类定义的。没有static是,b调用的是对象的方法,而b是用A类new的。
重写:(发生在父子类)
1.方法名必须相同
2 参数列表必须相同
3修饰符 子类的大于等于父类的 public>protected>default>private
4 抛出的异常范围得比父类的小
子类的方法和父类的方法必须一致,方法体不同
为什么需要重写?
父类的功能,子类不一定需要,或者不一定满足
多态
即同一方法可以根据发送对象的不同而采用不同的行为方式
package com.polymorphism;
public class Person {
public void run(){
System.out.println("run");
}
}
package com.polymorphism;
public class Student extends Person {
import com.polymorphism.Person;
import com.polymorphism.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的 比如new Person() new Student()
//可以指向的引用类型就不确定了:父类的引用指向子类
Person p1 = new Person();
//Student是子类,能调用的方法是自己的或是父类的
Student s1 = new Student();
//Person是父类,可以指向子类,但不能调用其方法
Person s2 = new Student();
//对象能执行那些方法主要看等号左边的引用类型 和右边关系不大
p1.run();
s1.run();//子类若是没有重写父类方法,则调用父类的;重写后调用子类的。
s2.eat();// 报错 Person中没有eat方法
}
}
注意事项:
多态是方法的多态,属性没有多态
父类和子类,有联系,类型转换异常:ClassCastException!
多态存在条件:有继承关系,方法需要重写
什么方法不能重写?
static 属于类,不属于实例
final 常量
private 私有的
Instanceof
判断两个类是否存在父子关系
Object object = new Student(); //object指向的对象是student类型的
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false
System.out.println("===================");
Person person = new Student();//person指向的对象是Student类型的
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Teacher);//false
System.out.println(person instanceof Object);//true
System.out.println("================");
Student student= new Student();//person指向的对象是Student类型的
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Student);//true
/* System.out.println(student instanceof Teacher);*///编译不通过,爆红。原因是 student类和 teacher无关系
System.out.println(student instanceof Object);//true
System.out.println(x instanceof y);
1 能否编译通过看类,x和y的类 若存在父子关系 则能编译通过
2 编译通过后 true或false看引用指向的对象 x只想的对象如果是后面y的子类 及时true
Person person = new Student();
System.out.println(person instanceof Person);
比如 person 的类是Person
引用指向的对象是Student
类型转换
父类转子类 向下转型 强制转换 可能会丢失一些方法
//高转底
Person person = new Student();
Student aa = (Student)person;
Person person1 = new Person();
Student aasd = (Student)person1;
子类转父类 向上转型
Student student = new Student();
Person person = student;
Static
public class StaticTest {
//属性
private int a;
private static double b;
//方法
private void run(){
System.out.println("run");
}
private static void go(){
System.out.println("go");
}
public static void main(String[] args) {
//调用
//非静态属性 通过类对象调用
StaticTest staticTest = new StaticTest();
System.out.println(staticTest.a);
//静态属性 通过类名直接调用
System.out.println(StaticTest.b);
//非静态方法调用
staticTest.run();
//静态方法
StaticTest.go();
}
}
执行顺序
注意:static只执行一次
public class CodeArea {
{
System.out.println("匿名代码块");
//一般附一些初始值
}
static {
System.out.println("静态代码块");
}
//构造方法
public CodeArea() {
System.out.println("构造方法");
}
public static void main(String[] args) {
CodeArea codeArea = new CodeArea();
}
}
//结果
静态代码块
匿名代码块
构造方法
抽象类
1.不能new抽象类 只能靠子类趋实现 约束。子类继承抽象类就得必须实现他的所有方法。
2 抽象类中可以写普通方法
3抽象方法必须写在抽象类中。
接口
接口实现类命名 ***Impl
侧面实现多继承,接口只有方法的定义。
一个类可以实现多个接口,但只能继承一个类。
接口作用:
1 约束
2 定义一些方法 让不同人去实现
3 接口方法默认是public abstract
属性默认是常量 public static final
4 接口不能被实例化 接口没有构造方法
内部类
内部类 就是一个类的内部定义一个类,比如A类中定义一个B类,n那么B类相对A类来说就是内部类,A相对于B类来说就是外部类
1 成员内部类
public class outer {
private 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);
}
}
}
public class application {
public static void main(String[] args) {
outer outer = new outer();
outer.out();
//通过外部类实例化内部类
com.innerclass.outer.inner inner = outer.new inner();
inner.getId();
}
}
2 静态内部类
public class outer {
private int id = 10;
public void out(){
System.out.println("外部类");
}
public static class inner {
public void in(){
System.out.println("静态内部类");
}
//静态内部类不能访问外部类的属性
}
}
3 局部内部类
public class MemberClass {
//局部内部类 写在方法中的
public void method(){
class MemberInner{
public void aa(){
System.out.println();
}
}
}
}
4 匿名内部类
public class Test {
public static void main(String[] args) {
//没有名字初始化类 不用将实例保存在变量中
new Apple().eat();
//一般是先实例化
/*Apple apple = new Apple();
apple.eat();*/
//接口也可以
new UserService(){
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?