文章目录
内存分析简单介绍
-
栈
- 大小:区域小,大概2m左右。
- 空间释放:通过栈顶指针移动的。
- 存储内容:(1) 基本数据类型. (2) 引用类型。
- 堆
- 存放 栈 当中引用指向的类对象。
- 方法区
- 存放:类信息,静态的变量,成员方法,常量。
- pc 寄存器
- 保存是当前正在执行的
JVM
指令的地址。 - 每个线程启动时,都会创建一个
PC
寄存器。
- 保存是当前正在执行的
- 本地方法栈
- 保存本地(native)方法的地址。
构造方法
- 建议自定义无参构造方法,避免形成对编译器的依赖。
方法重载
- 方法名相同,参数列表不同(顺序,长度,类型)。
- 和返回类型无关。
static 关键字
静态成员变量 / 方法
- 所有类实例共享.
- 静态方法当中不能访问非静态成员。
代码块
-
普通代码块:执行流程当中出现。
-
构造代码块:在类的成员位置,在每次对象创建的时候执行,执行在构造方法之前。
-
静态代码块:类加载的时候执行,每次程序启动到关闭,只会执行一次。
-
同步代码块:多线程当中使用锁形成临界区。
构造方法,构造块,静态块的执行顺序
- 静态代码块 > 构造块 -> 构造方法。
- 相同类的静态代码块,前面的先执行,后面的后执行。
- 相同类的构造块,前面的先执行,后面的后执行。
- 父类静态代码块先于子类静态代码块执行。
- 父类构造块先于子类构造块执行。
public class Demo01 extends Demo{
public Demo01() {
System.out.println("子类构造");
}
static {
System.out.println("子类静态代码块1");
}
static {
System.out.println("子类静态代码块2");
}
{
System.out.println("子类构造块1");
}
{
System.out.println("子类构造块2");
}
public static void main(String[] args) {
new Demo01();
// 父 static1 -> 父类 static2 -> 子类staticc1-> 子类static2 ->
// 父类构造块1 -> 父类构造块2 -> 父类构造方法。
// 子类构造块1 -> 子类构造块2 -> 子类构构造方法
}
}
class Demo {
public Demo() {
System.out.println("父类构造");
}
static {
System.out.println("父类静态代码块1");
}
static {
System.out.println("父类静态代码块2");
}
{
System.out.println("父类构造块1");
}
{
System.out.println("父类构造块2");
}
}
父类静态代码块1
父类静态代码块2
子类静态代码块1
子类静态代码块2
父类构造块1
父类构造块2
父类构造
子类构造块1
子类构造块2
子类构造
权限修饰符
抽象类
- 抽象类必须使用
abstract class
声明。 - 抽象类中可以没有抽象方法。
- 抽象类不能被实例化。
abstract
关键字修饰的抽象方法必须为public / protected
,因为private
方法不能被子类重写。- 抽象类可以有成员和构造方法。
- 如果一个类实现抽象类的,要么实现其全部抽象方法,要么声明自己为抽象类。
继承
方法重写中注意事项
- 两同:重写的方法有相同的方法名称和参数列表。
- 返回类型:子类方法返回类型必须比父类方法的返回值的类型更小(子类)或相等。
- 异常:子类方法声明中抛出的异常类要比父类方法声明抛出的异常更小(子类)或相等。
- 权限修饰:子类的方法的访问权限要比父类的方法的访问权限更大或相等。即,重写方法不能使用比被重写方法更严格访问权限。
接口
思想:
定义和实现分离。比如JDBC是一套接口,对于开发者来说,面向接口(定义)进行设计,数据库厂商则面向接口进行实现,这样就能使得设计出来的程序,在JDBC的实现层面上可替换。降低了程序和固定数据库的耦合。同样的,一个接口可以有多个厂商的不同实现来对同一套程序进行替换,也实现了一种高度可扩展性。
全局常量
// 全写
public static final String INFO = "内容"
// 简写
String INFO = "内容"
抽象方法
// 全写
public abstract void print() ;
// 简写
void print();
多继承,多实现
- 接口因为都是抽象部分,不存在具体的实现, 所以允许多继承
class 子类 implements 父接口1,父接口2...{
}
interface C extends A,B{
}
接口 和 抽象类区别
- 抽象类被子类继承,接口被子类实现。
- 接口只能声明抽象方法和常量,抽象类可以有构造方法和成员属性。
- 抽象类无法多继承,接口之间多继承多实现均可。
- 抽象类可以有
static
方法,但是接口当中不允许有static
方法(JDK1.8)。 - 作用 : 接口是一套规范:比如JDBC。抽象类做适配工作,减少使用者需要实现接口的代码数量。
多态
关键
- 父类指向子类,在运行时调用具体指向实现类的方法。
表现
- 重载和重写 是方法的多态:相同方法名的多种形态。
- 父子类之间多态(父引用指向子类实现):子类就是父类的一种形态 ,对象多态性。
向上 / 向下转型
· 向上转型:将子类实例变为父类实例
|- 格式:父类 父类对象 = 子类实例 ;
· 向下转型:将父类实例变为子类实例
|- 格式:子类 子类对象 = (子类)父类实例 ;
instanceof
- 作用:判断某个对象是否是指定类的实例。注意:子类实例 instanceof 父类是true。
Object 类
所有类都继承自Object
类。
toString
默认的toString 返回是对象内存地址的。
equals
比较两个对象是否相等
满足特性
:
自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后
x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象
上的equals比较中使用的信息。
非空性 :对于任何非空的参考值x , x.equals(null)应该返回false
简单示例
@Override
public boolean equals(Object o) {
// 比较地址
if (this == o) return true;
// o 不会空,且两者的类是同一个类
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age &&
Objects.equals(username, user.username) &&
Objects.equals(address, user.address);
}
@Override
public int hashCode() {
return Objects.hash(username, address, age);
}
内部类
分类
1、成员内部类
2、局部内部类
3、匿名内部类
4、静态内部类
成员内部类
- 定义在一个成员属性位置。
- 成员内部类无条件访问外部类的所有成员属性和成员方法。
class Outer {
private double x = 0;
public Outer(double x) {
this.x = x;
}
class Inner { //内部类
public void say() {
System.out.println("x="+x);
}
}
}
发生隐藏的解决方式
当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。
外部类.this.成员变量
外部类.this.成员方法
外部创建内部类
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
class Person{
public Person() {
}
}
class Man{
public Man(){
}
public People getPerson(){
class Student extends People{ //局部内部类
int age =0;
}
return new Student();
}
}
匿名内部类
匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一
个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐
式的。
注意事项
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或
者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
6、只能访问final型的局部变量。
静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法.
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
// 静态内部类
static class Inner {
public Inner() {
}
}
}
```