面向对象
面向对象编程的本质
以类的形式组织代码,以对象的形式封装(组织)数据。
static
public void a(){b();}public static void b(){a();//错误}
}
static和类一起加载,其他实例化才会加载。
构造器
new对象时候,本质是在调用构造器
无参构造:默认会提供无参构造。
有参构造:一旦构造了有参构造,无参构造必须显式定义。4
alt+insert生成构造器
内存分析
!
类方法和实例方法
1. 类方法——用static修饰的方法。
由于类方法是属于整个类的,不属于类的某一个实例(对象)
即类方法体有如下限制:
1.类方法中不能引用实例变量;
2.类方法中不能调用类的实例方法;
3.在类方法中不能调使用super,this关键字;
4.类方法不能被覆盖。
2.实例方法
实例方法
当一个类创建了一个对象后,这个对象就可以调用该类的方法(对象方法)。
1.实例方法中可以引用实例变量,也可以引用类变量;
2.实例方法中可以调用类方法;
3.对象方法中可以使用super,this关键字。
3.区别
1.类方法可以通过类名调用,实例方法不能通过类名调用。
2.静态内存是连续的,因为是在程序开始时就生成了,而实例申请的是离散的空间,所以当然没有静态方法快,而且静态内存是有限制的,太多了程序会启动不了。类方法常驻内存,实例方法不是,所以类方法效率高但占内存。
3.类方法不可被继承,因此子类中相同名字的类方法不能覆盖父类的类方法(?)
this和super
概念
this关键字用于指代当前对象实例本身。在Java中,当你创建一个类的实例(对象)时,this就是指向这个实例的引用。
用法
-
在构造方法中使用this,代表使用该构造方法创建的对象。
-
在实例方法中使用this,代表使用该方法的对象。
-
区分成员变量和局部变量:
如果在方法内局部变量的命名与实例变量的命名相同,根据内部屏蔽外部的原则,实例变量(外部调用)在这个方法内暂时失效。如果想在该方法中使用实例变量,则需要在变量名前显示的加上"this."用来指明此变量是实例变量。
void setleg(int leg){this.leg = leg; //此处利用this区分了实例变量与局部变量。}
- 类方法中不能使用this
类方法(或有static修饰的静态方法)中不能使用this关键字。因为这些方法是静态的,常驻内存。当程序执行,为这些方法在内存中开辟存储空间的时候,可能还没有任何对象诞生。this关键字也就失去了意义。
概念
super关键字用于从子类中访问父类的内容。当你创建一个子类对象时,它同时也包含了父类的所有内容(成员变量、成员方法等),super就是指向这个父类内容的引用。
用法
- 访问父类的成员变量:
如果子类覆盖了父类的成员变量,我们可以使用super来访问父类的成员变量。 - 调用父类的成员方法:
如果子类覆盖了父类的方法,我们可以使用super来调用父类的方法。 - 调用父类的构造方法:
在子类的构造方法中,我们可以使用super(…)来调用父类的构造方法。
区别
-
this引用的是当前对象本身,可以用来访问当前对象的成员变量、成员方法或返回当前对象本身。
-
super引用的是当前对象的父类对象,可以用来访问父类的成员变量、成员方法或构造方法。
-
在构造方法中,this(…)用于调用当前类的其他构造方法,而super(…)用于调用父类的构造方法。注意,这两者在构造方法中必须是第一条语句。
-
this和super都不能在静态方法、静态代码块或类变量声明中使用,因为它们都依赖于具体的对象实例。
使用this
关键字来调用本类中构造方法
// 无参数的构造方法
public Person() {this("Unknown", 0); // 调用带两个参数的构造方法
}
// 带一个参数的构造方法
public Person(String name) {this(name, 0); // 调用带两个参数的构造方法
}// 带两个参数的构造方法
public Person(String name, int age) {this.name = name;this.age = age;
}
通过使用this
关键字,我们可以减少代码的重复,并确保所有构造方法都正确地初始化对象。这是实现构造方法重用的一种常见方式。
封装
private:私有
属性私有,get/set
继承
定义
对一批类的抽象。
子类继承父类,用extends关键字。
所有类默认继承Object类。
一个类只可以直接继承一个父类,可以间接继承多个父类。(单继承)
super()和this()
super注意点:
-
super调用父类构造方法,必须在构造方法的第一个;
-
super和this不能同时调用构造方法;
this():本类构造
super():父类构造
构造器
public Student(){super();//默认隐藏SYstem.out.println("无参构造");
}
重写
需要有继承关系,子类重写父类方法!
- 方法名完全相同
- 参数列表必须相同
- 修饰符范围可以扩大:public>protected>default>private (静态无法重写)
- 抛出的异常:范围可以被缩小,不能扩大;(异常范围不能大于父类)
//静态方法和非静态方法区别很大!
//没有static时,b调用的对象的方法(没有B类静态方法),而B是使用A类new的
//有static时,b调用了B类的方法,因为b是用B类定义的
//因为静态方法是类的方法,而非静态是对象的方法。
//省流:先看左侧定义数据类型,若有静态方法则为静态方法调用,若无则为右侧对象方法//方法的调用只和左边定义的数据类型有关
A a =new A();
a.test();//A-test//父类的引用指向了字类
B b=new A();
b.test();//A-test
public class A extends B{@Override//重写public void test(){system.out.println("A-test");}
}
public class B{public void test(){//没有staticsystem.out.println("B-test");}
}
为什么重写?
父类功能子类不一定需要/不满足;
多态
用法
一个对象的实际类型是确定的,但是可以指向的引用类型不确定。如下:
Student s1=new Student();
Person s2=new Student();//父类的引用 指向 子类对象
Object s3=new Student();
public class Person {public void run(){System.out.println("run");}
}
public class Student extends Person{public void run(){System.out.println("studentnrun");//子类重写父类方法}
}
public class Application {public static void main(String[] args) {//调用自己的或者父类的Student s1=new Student();//可以指向子类,但是不能调用子类独有的方法 Person s2=new Student(//父类的引用 指向 子类对象。 若子类没有重写,则使用父类。若子类重写,使用子类。保证程序执行时候才知道结果如何,动态,灵活//若子类有方法而父类没有,则报错。(除非强制转换(Student)s2).eat())s1.run();//Student runs2.run();//Student run 字类重写父类方法,执行子类。}
}
注意事项:
- 多态是方法的多态,没有属性多态
- 父类和字类,有联系
- 子类重写父类方法,使用子类 父类引用指向子类对象 father f1=new Son();
方法不可重写:
- static 属于类,不属于实例
- final 常量
- private方法
instance of
X instanceof Y
能不能编译通过!看‘=’左边类型与instanceof后面的类型是否是继承关系。运行结果是true还是false,看‘=’右边与instanceof后面的类型是否是继承关系
Fu f = new Zi();//拥有了被Zi类函数覆盖后的Fu类对象----f------。
所以f所代表的是函数被复写后(多态的意义)的一个Fu类,而Fu类原来有的成员变量(不是成员函数不可能被复写)没有任何变化。
获得结论:
1、成员变量:编译和运行都看Fu。
2、非静态方法:编译看Fu,运行看Zi
3、静态方法:编译和运行都看Fu。
其实很简单,首先我们要理解静态情况下发生了什么?当静态时,Fu类的所有函数跟随Fu类加载而加载了。也就是Fu类的函数(是先于对象建立之前就存在了,无法被后出现的Zi类对象所复写的,所以没发生复写.
原文链接:https://blog.csdn.net/ChaoticNg/article/details/93176680
强制转换
父类的引用 指向 子类对象。
把子类转化为父类,向上转型;
把父类转化为子类,向下转型;强制转换。强制转换可能丢失方法。
强制转换(Student)s2).eat()。
static
匿名代码块:对象创建就会执行(可以用来赋初始值)
静态代码块:只执行一次。
抽象类
抽象类的所有方法必须由其子类实现,除非其继承子类仍然为抽象类。
抽象类中可以包含普通方法,但一旦有抽象方法就是抽象类。
//abstract抽象类 :类 extends:单继承 (接口可以多继承)public abstract class Action{//抽象方法,只有方法名字,没有方法实现public abstract void doSomething();
}
特点:不能new抽象类,只能靠子类去实现他 : 约束!
抽象类包含构造器,子类继承父类后仍然需要父类构造器
接口
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有!
接口:只有规范。 约束和实现分离。
接口就是规范,定义的是一组规则。接口的本质是契约。
//接口都需要有实现类
public interface UserService{//常量public static final int AGE=99;int AGE=99;//相同(不常用常量)//接口中所有定义都是抽象的 public abstractvoid add(String name);void delete(String name);
}
public interface TimeService{void timer();
}
//实现接口的类 就需要重写接口中的方法
public class UserServiceImpl implements UserService,TimeService{@overridepublic void add(String name){}@overridepublic void delete(String name){}@overridepublic void timer(){}
}
作用:
- 约束
- 定义一些方法,让不同人实现
- 接口中所有定义都是抽象的 public abstract
- 接口中所有常量都是public static final
- 不可以被直接实例化,没有构造方法(抽象类有构造方法)
内部类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
public class Outer{private int id;public void out(){System.out.println("外部类");}public class Inner{public void in(){System.out.println("内部类");}//内部类可以直接获得外部类的私有属性和方法,不用创建外部类对象public void getID(){System.out.println(id); }}
}
Outer outer=new Outer();
//通过外部类来实例化内部类
Outer.Inner inner=outer.new Inner();
inner.in();
内部类可以直接获得外部类的私有属性和方法,不用创建外部类对象
局部内部类:
public class Outer{public void method(){class Inner{ //局部内部类}}
}
//一个java类中可以有多个class类,而只能有一个public class类
class A{
public static void main(String[] args){
}
}
匿名内部类
public class Test{
public static void main(String[] args){//没有名字初始化类,不用将实例保存到变量中new Apple().eat();}
}
class Apple{public void eat(){}
}