【JAVA学习】二.面向对象基础

二、面向对象基础

1.对象(object,instance):在内存中是一个内存块,用来表示相关联的数据,其中包括对象的属性和方法。
2.类(class):可以看作对象的模板,是对象的抽象。
3.一个类可以是另一个类的属性。
4.内存分析:

java虚拟机的内存可以分为三个区域:栈stack,堆heap,方法区method area。
栈:

  1. 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(局部变量,操作数,方法出口)。当一个方法被调用的时候该方法进栈,当该方法中又会调用其他方法时,再把其他方法进栈。其他方法执行完之后出栈,该方法继续执行。
  2. JVM会为每一个线程创建一个栈。线程执行完之后,这个栈就被关闭。
  3. 栈属于线程私有,不能实现线程间的共享。
  4. 先进后出,后进先出。
  5. 栈是系统自动分配,速度很快,是一个连续的内存空间。
  6. JVM只有一个堆,被所有线程共享。
  7. 用于存储创建好的对象和数组(数组也是对象)。(new。。。就是放在堆里)
  8. 是一个不连续的空间,分配灵活但是速度慢。
    方法区(静态区)
  9. JVM只有一个方法堆,被所有线程共享。
  10. 实际上也是堆,只是用于存储类,常量相关的信息。
  11. 用来存放程序中永远不变或唯一的内容。(类信息,静态变量,字符串常量)
    在这里插入图片描述
5.构造方法/构造器(constructor),用于对象的初始化。
  1. 构造方法和类名称一致,通过New关键调用。
  2. 虽然有返回值 ,但是不需要声明返回类型。
  3. 如果没有定义构造方法,编译器会添加一个无参构造器。如果已定义方法,则不会生成无参构造器!!!
6.构造方法重载
  1. 传入的参数和类中定义的属性名称一样,使用就近原则,表示的是传入的参数。如果这个时候想要表示类中的属性,需要在前面加this.。
  2. 构造方法的第一句总是super();
7.垃圾回收机制

有一个”服务员“GC,自动回收垃圾。

  1. 发现无用的对象。
  2. 回收无用对象占用的内存空间。
    相关算法:
  3. 引用计数法:每个对象有一个引用计数,被引用一次计数加一,被引用变量值变为null,计数减一。直至0变成无用对象。缺点是循环引用的无用对象无法识别。
  4. 引用可达法:把程序所有的引用关系看成一张图。
8.分代垃圾回收机制

将对象分为三种状态:年轻代,年老代,持久代。虚拟机将内存划为Eden,Survivor和Tenured

  1. 年轻代
    所有新生成的对象首先放在Eden区,目的是尽可能快的手机掉生命周期短的对象,对应的是Minor GC。
  2. 年老代
    在年轻代中经历了N(15)次垃圾回收后仍然存活的对象就会被放到年老代中。当年老代对象过多,就要启动Major GC和Full GC来一次大扫除,全面清理年轻代和年老代的区域。
  3. 持久代
    用于存放静态文件,如Java类,方法等。
垃圾回收过程
  1. 新建的对象,大部分放在Eden中。
  2. 当Eden满了,触发垃圾回收机制(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中(S1),清空Eden区。
  3. 当Eden再次满了之后,将S1中不能清空的对象放在另一个Survivor中(S2),同时将Eden中不能清空的对象方在S1中保证Eden和S1均被清空。
  4. 重复多次Survivor中没有被清理的对象,放在年老代(Tenured)中
  5. 当年老代满了之后,触发一次完整的垃圾回收(Full GC),之前新生地的垃圾回收为(minor GC)
  6. 使用代码System.gc()可以建议启动GC,但是只是建议没有决定权
容易造成内存泄漏的操作
  1. 创建大量的无用对象
  2. 静态集合类的使用:HashMap,Vector等使用最容易造成内存泄漏,他们的生命周期和应用程序一致。
  3. 各种连接对象(IO流对象,数据库连接对象,网络连接对象)未关闭。
  4. 监听器的使用
9.对象创建的过程和this的本质
  1. 分配对象空间,并将对象成员变量初始化为0或空
  2. 执行属性值的显式初始化
  3. 执行构造方法
  4. 返回对象的地址给相关变量
    this的本质就是创建好的对象的地址,在构造方法调用前,对象已经创建,所以在构造方法中可以使用this代表当前对象。
    this不能用于static方法中,因为this指当前对象而static方法在方法区中。
10.static关键字(静态)

它声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同, 在整个应用程序执行期间都有效。static修饰的成员变量和方法从属于类,普通变量和方法从属于对象。

11.静态初始化块

构造方法用于对象初始化,静态初始化块用于类的初始化。在静态初始化块中不能直接访问非static成员。
初始化快的执行顺序和继承有关,上溯到Object类,先执行父类的静态初始化块。
static{
这里面不能调用非静态的方法和属性
}
静态快在类加载的时候执行,也就是在构造器之前执行。

12.参数传值机制

JAVA中方法所有参数的传递都是值传递,传递的是值的副本。副本的改变不会影响原参数。

基本数据类型参数的传递

传递的是值的副本,副本改变不会影响原件。

引用类型参数的传值

传递的是对象的地址,因此,副本的改变也会导致原件的改变。

13. java包机制

类似于文件夹的概念。一般是域名倒着写。调用不同包下的文件需要import。

包同名
import java.util.Date
import java.sql.*

java.sql.Date a = new java.sql.Date();

sql和util中都有Date,直接new默认的Date是显示指定的util中的Date,如果想用sql中的Date需要这样写。

静态导入

用于导入指定类的静态属性, import static java.lang.Math.PI。PI就可以直接使用不需要加Math。

14.继承(extends)

继承是子类对父类的扩展实现了代码的重用,但是父类的东西未必都能用。

  1. 父类也称作,超类,基类或者派生类。
  2. Java中只有单继承,只有一个直接父类。不像C++
  3. 虽然类没有多继承,但是接口可以多继承。
  4. 子类继承父类可以得到父类全部的属性和方法(除了父类的构造方法),但未必可以直接访问,比如父类的私有属性和方法。
  5. 定义一个类时没有调用extends,它默认的父类是:java.lang.Object。
  6. 使用instanceof判断子类的对象是否是父类类型结果是true。反过来是false。
15.重写(override)

子类重写父类的方法,让子类自身的行为替换父亲的行为。

  1. 方法名,形参列表相同
  2. 返回值类型要小于等于父类类型(返回值类型可以是父类类型的子类或本身)。
  3. 访问权限,子类大于父类。
16.Object类

是所有Java类的根基类,所有的Java对象都拥有Object类的属性和方法。

toString方法

我们在打印一个对象时,会默认调用toString方法。

17.equals方法的重写

“==”表示比较双方是否相同,如果是基本类型则表示值相等。如果是引用类型则表示地址相等,即同一个对象。
equals方法用于判断对象的内容是否相等的逻辑。
默认的equals方法就是比较两者的地址是否相同。

18.super方法

是直接父类对象的引用,可以通过super访问父类中被子类覆盖的方法和属性。
构造方法的第一行如果没有显式的调用super(),那么java会默认调用super(),含义是调用父类的构造方法。

继承树追溯
class Solution {
    public static void main(String[] args) {
        System.out.println("开始创建对象");
        Child a = new Child();
    }
}
class Father{
    public Father(){
        System.out.println("父类构造");
    }
}
class Child extends Father{
    public Child(){
        System.out.printf("子类构造");
    }
}

在这里插入图片描述
这是因为构造方法的第一句总是,super();
属性/方法的查找顺序:

  1. 查找当前类中有没有属性h。
  2. 依次上溯每个父类,查看每个父类中是否有h,直到Object。
  3. 如果没有找到,则出现编译错误。
  4. 上面步骤,只要找到h变量,则这个过程终止。
19.封装(Encapsulation)

高内聚,低耦合

  1. 提高代码的安全性
  2. 提高代码的复用性
  3. 高内聚:封装细节,便于修改内部代码,提高可维护性
  4. 低耦合:简化外部调用,易于扩展和协作
访问控制符
  1. private 表示私有,只有自己可以看见
  2. default(默认)表示没有修饰符修饰,只有同一个包的类能访问
  3. protected 表示可以被同一个包的类以及其他包的子类访问
  4. public 可以被该项目的所有包的所有类访问
使用细节
  1. 类的属性一般是private访问权限
  2. 提供相应的get/set方法访问相关变量,这些方法通常用public修饰,提供对属性的赋值和读取操作
  3. 一些只用于本类的辅助方法可以用private修饰,希望其他类调用的方法用publice修饰。
20.多态(polymorphism)

多态指同一个方法的调用,由于对象不同可能会有不同的行为。同一方法,具体的实现会完全不同。

  1. 方法多态,属性没有多态
  2. 多态的存在有三个条件:继承,方法重写和父类引用指向子类对象
  3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了
21.对象的转型(casting)
  1. 自动向上转型:可以把子类对象赋值给父类,向上转型后的父类引用变量只能调用它编译的方法,不能调用它运行时类型的方法。(只能调用父类中的方法)
  2. 强制向下转型:可以把向上转型的对象再转回来。
  3. 把不同的子类向上转型再向下转型为不同的子类,编译器不会报错但是运行时会报错。
22.final关键字
  1. 修饰变量:被他修饰的变量不可改变,一旦赋了初值就不能被重新赋值。
  2. 修饰方法:不能被子类重写,但可以重载。
  3. 修饰类:不能被继承。
23.数组的使用

数组是相同类型数据的有序集合。描述的是相同类型的若干数据,按照一定的先后次序排序组合。每一个数据称为元素,可以通过索引访问。

  1. 长度是确定的,大小不可改变
  2. 元素必须是相同类型
  3. 数组类型可以是任何数据类型,包括基本类型和引用类型
  4. 数组变量是引用类型
  5. 数组就是对象,其中的每个元素相当于该对象的成员变量
  6. 数组是连续存储的
    在这里插入图片描述
数组初始化方法
  1. 静态初始化 int[] a = {1,2,3}; User[] b = {new User(1,"a"),new User(2,"b");}
  2. 默认初始化:int[] a = new int a[2];数组是引用类型,它的元素相当于类的实例变量,因此数组在分配空间后,各个元素也按默认值隐式初始化。
  3. 动态初始化:在默认初始化之后通过下标赋值。
数组的遍历

for-each循环是专门用于读取数组的

for (int m: a){
	System.out.println(m);
}
24.抽象方法和抽象类
抽象方法

使用abstract修饰的方法,没有方法体,只有声明。但是会告诉子类必须给抽象方法提供具体的实现。

抽象类

包含抽象方法的类,必须是抽象类。但是抽象类中可以定义普通方法。抽象类不能实例化,不能new只能被用来继承。

abstract class Solution {
    abstract public void a();
    public void run(){
        System.out.println("run");
    }

    public static void main(String[] args) {
        Solution x = new Abc();
        x.run();
        x.a();
    }
}
class Abc extends Solution{
    @Override
    public void a() {
        System.out.println("aaa");
    }
}
25. 接口
为什么需要接口,它和抽象类有什么区别

比抽象类还要抽象的抽象类,可以更加规范的对子类进行约束。全面的实现了规范和具体实现相分离。
接口不提供任何实现,所有方法都是抽象方法。
从接口的实现者角度看,接口定义了可以向外部提供的服务。
从接口的调用者角度看,接口定义了实现者能提供哪些服务。
接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的实现了。系统的实现就是面向接口编程的。
接口的父子类不是父子关系,而是实现规则关系。

如何定义和使用接口
  1. 访问修饰符只能是public或者默认
  2. 接口名和类名采用相同命名机制
  3. extends:接口可以多继承(使用extends继承多个接口)
  4. 常量:接口中的属性只能是常量,总是:public static final修饰,不写默认也是。
  5. 方法:接口中的方法只能是:public abstract,不写默认也是。
  6. 子类通过implements实现接口中的规范
  7. 接口不能声明实例,但是可以用于声明引用变量类型
  8. 一个类实现了接口,必须实现类中的所有方法,并且这些方法只能是public的
面向接口编程

接口就是规范,是项目中最核心的东西。

26.内部类

成员内部类(非静态内部类,静态内部类),匿名内部类和局部内部类

成员内部类(可以使用private,default,protected,public任意修饰)
a.非静态内部类
  1. 必须寄存在一个外部类对象里。因此一个内部类对象一定存在一个外部类对象。非静态内部类对象独立于外部类的某个对象。
  2. 非静态内部类可以直接访问外部类成员,但是外部类不能直接访问非静态内部类成员。
  3. 非静态内部类不能有静态方法静态属性和静态初始化块。
  4. 外部类的静态方法,静态代码块不能访问非静态内部类。
    class Solution { public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner(); inner.show(); } } class Outer{ private int age = 10; public void testOuter(){ } class Inner { int age = 20; public void show(){ int age = 30; System.out.println("外部类成员变量:" + Outer.this.age); System.out.println("内部类成员变量:" + this.age); System.out.printf("局部变量:" + age); } } }
b.静态内部类

用的不多。

27.String类
  1. 称作不可变字符序列。
  2. 位于String.lang包下。
常量池

字符串常量会放在常量池里。

class Solution {
    public static void main(String[] args) {
        String str = "abc";
        String str2 = new String("abc");
        String str3 = "abc" + "def";
        String str4 = "18" + 19;
        String str5 = "abc";
        System.out.println(str4);
        System.out.println(str == str2);
        System.out.println(str == str5);
        System.out.println(str.equals(str2));
    }
}

在这里插入图片描述

常用方法
  1. str.charAt(x);提取下标为x的字符
  2. str.equals(str2);比较两个字符串是否相等
  3. str.equalsIgnoreCase(str2);比较两个字符串是否相等(忽略大小写)
  4. str.indexOf(“java”)返回字符串第一次出现的位置,如果不存在返回-1
  5. str.replace(’ ',‘a’)将str中的全部空格用a代替
  6. str.startsWith(“abc”)判断str是否以abc开头
  7. str.endsWith(“abc”)同上
  8. str.substring(4)从下标为4开始到字符串结束
  9. str.substring(4,7)提取子字符串下标[4,7)不包括7
  10. str.toLowerCase()全转小写
  11. str.toUpperCase()全转大写
  12. str.trim() 去掉首尾空格
28.数组的拷贝

System.arraycopy(s1,2,s2,6,3) 从s1的第二个元素开始拷,拷三个,从s2的下标6开始放。

在数组中删除元素

本质上也是数组的拷贝

29. Arrays工具类
import java.util.Arrays;
class Solution {
    public static void main(String[] args) {
        int[] a = {10,30,20};
        System.out.println(a);
        System.out.println(Arrays.toString(a));
        Arrays.sort(a);
        System.out.println(Arrays.toString(a));
        //二分法查找
        System.out.println(Arrays.binarySearch(a,30));
        System.out.println(Arrays.binarySearch(a,4));
    }
}

在这里插入图片描述

30. 多维数组
class Solution {
    public static void main(String[] args) {
        //二维数组每一个元素的长度可以不一样
        int[][] a = new int[3][];
        a[0] = new int[]{20,30,40};
        a[1] = new int[]{1,2};
        a[2] = new int[]{3,4};
    }
}
31.二分法查找
class Solution {
    public static void main(String[] args) {
        int[]arr = {30,20,50,10,80,9,7,12,100,40,8};
        Arrays.sort(arr);
        int low = 0;
        int high = arr.length -1;
        int value = 10;
        while (low<=high){
            int mid = (low + high) / 2;
            if (value == arr[mid]){
                System.out.println(mid);
                break;
            }
            if (value > arr[mid]){
                low = mid + 1;
            }
            if (value < arr[mid]){
                high = mid - 1;
            }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值