面向对象
文章目录
- 面向对象
- 面向过程和面向对象
- 对象的进化史(数据管理和企业管理共同之处)
- 对象和类的概念
- 类:
- 对象:
- 面向对象的内存分析
- 栈stack的特点:
- 堆heap的特点:
- 方法区(又叫静态区)特点:
- 构造方法
- 要点:
- 构造方法的重载
- 垃圾回收机制(Garbage Collection)
- 内存管理
- 垃圾回收过程
- 垃圾回收相关算法
- **2.引用可达法(根搜索算法)**
- 通用的分代垃圾回收机制
- JVM调优和Full GC
- 开发中容易造成内存泄漏的操作
- 创建大量无用对象
- 静态集合类的使用
- 各种连接对象(IO流对象、数据库连接对象,网络连接对象)未关闭
- 监听器的使用
- 要点:
- 对象创建的过程和this的本质
- ##### 创建一个对象分为如下四步:,,1. 分配对象空间,并将对象成员变量初始化为0或空,2. 执行属性值的显示初始化,3. 执行构造方法,4. 返回对象的地址给相关变量
- this关键字
- static关键字
- 静态初始化块
- 参数传值机制
- 引用类型参数的传值
- Java包(package)概念
- 继承的实现(extends)
- instanceof运算符
- 方法的重写override
- Object类
- toString()方法
- ==和equals方法
- super
- 继承树追溯
- 构造方法调用顺序;
- 封装的作用和含义
- **“高内聚,低耦合”**
- 封装的优点:
- 封装的实现——使用访问控制符
- 封装的使用细节
- 类的属性的处理:
- 多态(polymorphism)
- 多态的要点:
- 对象的转型(casting)
- final关键字
- 数组概述和特点
- 数组的三个基本特点:
- 注意事项:
- 抽象方法和抽象类(abstract)
- 抽象类的使用要点:
- 接口的作用
- 定义接口的详细说明:
- 要点:
- 内部类的分类
- 非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)
- 成员变量访问要点:
- 静态内部类
- 匿名内部类
- String基础
- String类和常量池
- 全局字符串常量池(String Pool)
- class文件常量池(Class Constant Pool)
- 运行时常量池(Runtime Constant Pool)
- String类常用方法
- 数组的拷贝
- arrayCopy
- Arrays工具类的使用
- 冒泡排序的基础算法
- 二分法查找(折半查找)
面向过程和面向对象
面向过程和面向对象都是软件分析、设计和开发的一种思想,它指导着人们以不同的方式去分析、设计和开发软件。
面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”并将步骤对应成方法,一步一步,最终完成。
这个适合简单任务,不需要过多协作的情况下。比如,如何开车?
对象的进化史(数据管理和企业管理共同之处)
事物的发展总是遵循“量变引起质变”的哲学原则;企业管理和数据管理、甚至社会管理也有很多共通的地方。
- 数据无管理时代
- 例如:初级公司一人身兼多职,但当业务量大时无法管理
- 数组管理和企业部门制
- 相同数据放到同一数据中,相当于部门,数组也是对象
- 对象和企业项目制
- 对象包含不同类型的变量,还可以有各种方法,相当于独立公司
对象和类的概念
类可以看做是一个模板,或者图纸,系统根据类的定义来造出对象。
类:
我们叫做class。
对象:
我们叫做Object,instance(实例)。
以后我们说某个类的对象,某个类的实例。是一样的意思。
public class Stu{
/*
属性filed,成员变量
方法
*/
int id;
String name;
int age;
Computer comp;//电脑
void speak(){
System.out.println("说话");
}
void study(){
System.out.println("使用"+comp.brand);
}
/*无参的构造方法 用于创建这个类的对象,无参的构造方法可以由系统自动创建*/
Stu(){
}
public static void main(String[] args){
/*实例化对象*/
Stu stu = new Stu();//创建一个对象 通过构造方法来创建类
stu.id=1;
stu.name="junwei";
Computer c1 = new Computer();
c1.brand = "ThinkPad";
stu.comp = c1;
stu.study();
}
}
class Computer{
String brand;//品牌
}
面向对象的内存分析
Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area
栈stack的特点:
- 栈描述的是方法执行的内存模型。每个方法都被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
- JVM为每一个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变变量等)
- 栈属于线程私有。不能实现线程间的共享
- 栈的存储特性是“先进后出,后进先出”
- 栈是由系统自动分配,速度快!栈是一个连续的内存空间
堆heap的特点:
- 堆用于存储创建好的对象和数组(数组也是对象)
- JVM只有一个堆,被所有线程共享
- 堆是一个连续的内存空间,分配灵活,速度慢
方法区(又叫静态区)特点:
- JVM只有做一个方法区,被所有线程共享
- 方法区实际也是堆,只是用于存储类、常量相关的信息
- *用来存放程序中永远是不变或唯一的内容。(类信息,class对象,静态变量,字符串常量等)
构造方法
构造器也叫构造方法(constructor),用于对象的初始化、
要点:
- 通过new关键字调用
- 构造器虽然有返回值,但是不能定义返回值类型(返回值得类型肯定是本类),不能再构造器里使用return返回某个值
- 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加。
- 构造区的方法名必须和类名一致。
构造方法的重载
构造方法重载和方法的总在要素一样
- 构造方法的第一句总是super()
- this表示创建好的对象
垃圾回收机制(Garbage Collection)
内存管理
- Java的内存管理很大程度值得就是对象的管理,其中包括对象空间的分配和释放。
- 对象空间的分配:使用new关键字创建对象即可
- 对象空间的释放:将对象赋值null即可。垃圾回收器将负责回收所有“不可达”对象的内存空间
垃圾回收过程
任何一种垃圾回收算法一般都要做两件基本事情:
- 发现无用的对象
- 回收无用对象占用的内存空间
垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用对象。Java的垃圾回收器通过其相关算法发现无用对象,并进行清除和整理
垃圾回收相关算法
- 引用计数法
堆中每个对象有一个引用计数。被引用一次,计数加1,被引用变量值为null,则计数减1,值到计数为0,则表示变成无用对象。优点是算法简单,缺点是“循环引用的无用对象”无法识别
public class Student{
String name;
Student friend;
public static void main(String[] args){
Student s1 = new Student();
Student s2 = new Student();
s1.friend = s2;
s2.friend = s1;
s1 = null;
s2 = null;
}
}
s1和s2互相引用对方,导致他们引用计数不为0,但是实际已经无用,但无法被识别。
2.引用可达法(根搜索算法)
程序把所有的引用关系看做一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当然所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用的节点,即无用节点。
通用的分代垃圾回收机制
我们将对象分为三种状态:年轻代、年老代、持久代(存在方法区里)
JVM将堆内存划分为Eden、Survivor和Tenured/Old空间。
- Eden区:存储了从未通过垃圾回收的新对象
- Survivor区:存放垃圾回收后,仍然有用的对象,循环存放,小鱼15次垃圾回收次数
- Tenured区:年老代区域存放超过15次垃圾回收的对象
- 新建对象存在在Eden中,当Eden满了,不能创建新对象,则触发垃圾回收(GC),将无用的清理掉,然后剩余对象赋值到Survivor中,以此类推。当old区满了,则会触发一个一次完整的垃圾回收
- Minor GC:用于清理年青代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象赋值到“Suvivor1”、“Suvivor2”区中(这两个区,大小空间相同,同一时刻Suvivor1和Suvivor2只有一个在用,一个为空)
- Major GC:用于清理老年代区
- Full GC:用于清理年青代、年老代区域。成本较高,会对系统性能产生影响(通长堆垃圾回收机制的优化,是对此进行优化)
JVM调优和Full GC
在对JVM调优的过程中,很大一部分工作就是对Full GC的调节。有如下原因可能导致Full GC:
- 年老代(Tenured)被写满
- 持久代(Perm)被写满
- System.gc()被显式调用(程序建议GC启动,不是调用GC 只是建议,并不是调用)
- 上一次GC后Heap(堆)的各域分配策略动态变化
开发中容易造成内存泄漏的操作
如下四种情况时最容易造成内存泄漏的场景,开发时一定注意:
创建大量无用对象
比如,我们在需要大量拼接字符串时,使用了String而不是StringBuilder。
String str = "";
for(int i = 0; i < 1000; i++){
str += i;//相当于产生了1000个String对象
}
静态集合类的使用
象HashMap、Vector、List等的使用最容易出现内存泄漏,这些静态变量的生命周期和应用程序一致,所有的对象Objec也不能被释放。
各种连接对象(IO流对象、数据库连接对象,网络连接对象)未关闭
IO流对象、数据库连接对象、网络连接对象等连接对象属于物理连接,和硬盘或者网络连接,不使用的时候一定要关闭。
监听器的使用
释放对象时,没有删除相应的监听器。
要点:
- 程序员无权调用垃圾回收器
- 程序员可以调用System.gc(),该方法只是通知JVM,并不是运行垃圾回收器。尽量少用,会申请启动Full GC,成本高,影响系统性能。
- finalize方法,是Java提供给程序员用来释放对象或资源的方法,但是尽量少用。
对象创建的过程和this的本质
##### 创建一个对象分为如下四步:,1. 分配对象空间,并将对象成员变量初始化为0或空,2. 执行属性值的显示初始化,3. 执行构造方法,4. 返回对象的地址给相关变量
this关键字
this的本质就是“创建好的对象的地址”由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象”。
区分成员变量和局部变量
**this调用构造器 this(a,b,c) 且构造器的调用只能在第一句 **
this不能用于static方法中
static关键字
在类中,用static声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个引用程序执行期间都有效。
static修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象。
- 在类中,用static声明的成员变量为静态成员变量,或者叫做:类属性,类变量。
- 它为该类的公有变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享。
- 可以使用“对象.类属性”来调用。不过,一般都是用“类名.类属性”
- static变量置于方法区中
- 用static声明的方法为静态方法
- 不需要对象,就可以调用(类名.方法名)
- 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非stati的成员。
- 静态方法不能以任何方式引用this和super关键字
静态初始化块
- 如果希望加载后,对整个类进行某些初始化操作,可以使用stati初始化块
- 类第一次被载入时先执行static代码块;类多次被加载时,static代码块只执行一次;static经常用来进行static变量的初始化
- 是在类初始化时执行,不能再创建对象时执行。
- 静态初始化块中不能访问非static成员。
参数传值机制
方法中所有参数都是“值传递”,也就是“传递的是值得副本”,不会影响原件
引用类型参数的传值
传递的是值得副本,但是引用类型指的是“对象的地址”。因此,副本和参数都指向了同一个“地址”,改变“副本指向地址的对象的值,也意味着原参数指向对象的值也发生了改变”
Java包(package)概念
包机制是Java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。包对于类,相当于文件夹对于文件的作用。
域名倒置
继承的实现(extends)
- 父类也称做超类,基类派生类等。
- Java中只有单继承,没有c++那样多继承。多继承会引起混乱,是得继承链过于复杂,系统按已维护
- Java中类没有多继承,接口有多实现
- 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
- 如果定义一个类时没有调用extends,则它的父类时:java.lang.Object.
instanceof运算符
instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则返回false
方法的重写override
- 方法名、形参列表相同
- 返回值类型和声明异常类型,子类小于等于父类
- 访问权限,子类大于等于父类
Object类
Object类是所有Java类的根基类,也就意味着所有的Java对象都拥有Object类的属性和方法
toString()方法
将HashCode转换为16进制输出
==和equals方法
- “==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。比较对象是否相同
- equals 比较内容是否相同
- Object类中定义有:public boolean equals(Object obj)方法,提供定义“对象内容相等”的逻辑。
- 比较两个对象的hashcode值
super
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
继承树追溯
构造方法调用顺序;
**构造方法第一句总是super(…)**来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复
封装的作用和含义
“高内聚,低耦合”
高内聚就是类的内部数据操作细节自己完成,不允许外不干涉
低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用
封装的优点:
- 提高代码安全性
- 提高代码复用性
- “高内聚”:封装细节,便于修改内部代码,提高可维护性。
- “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
封装的实现——使用访问控制符
修饰符 | 同一个类 | 同一个包中 | 不同包子类 | 所有类 |
private | * | |||
default | * | * | ||
protected | * | * | * | |
public | * | * | * | * |
- private 表示私有的的,只有自己类能访问
- default 表示没有修饰符,只有同一个包的类能访问
- protected 表示可以被同一个包的类以及其他包中的子类访问
- public 表示可以被该项目的所有包中的所有类访问
封装的使用细节
类的属性的处理:
- 一般使用private访问权限
- 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头)
- 一些只用于本类的辅助性方法可以用private修饰符,希望其他类调用的方法用public修饰。
多态(polymorphism)
多态指的是同一个方法调用,由于对象不同可能会有完全不同的行为。现实生活中,同一个方法,具体实现会完全不同。
多态的要点:
- 多态是方法的多态,不是属性的多态(多态与属性无关)
- 多态的存在要有3个必要条件:继承、方法重写、父类引用指向子类对象
- 父类引用指向子类对象后,用该类引用调用子类重写的方法,此时多态就出现了。
对象的转型(casting)
父类引用指向子类对象对象,我们称这个过程为向上转型,属于自动类型转换。
向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要进行类型的强制转换,我们称之为向下转型。
final关键字
- 修饰变量:被修饰的变量不可改变,一旦赋了初值,就不能被重新赋值
- 修饰方法:该方法不可被子类重写。但是可以被重载
- 修饰类:修饰的类不能被继承
数组概述和特点
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。
数组的三个基本特点:
- 长度是确定的。数组一旦被创建,它的大小就是不可以改变的
- 其元素必须是相同类型,不允许出现混合类型
- 数组类型可以是任何数据类型,包括基本类型和引用类型
数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当与该对象的成员变量。
注意事项:
- 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
- 声明一个数组的时候并没有数组真正被创建
- 构造一个数组,必须制定长度。
抽象方法和抽象类(abstract)
抽象类的使用要点:
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用
- 抽象类只能用来被继承
- 抽象方法必须被子类实现
接口的作用
定义接口的详细说明:
- 访问修饰符:只能是public或默认
- 接口名:和类名采用相同的命名机制
- extends:接口可以多继承
- 常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是
- 方法:接口中的方法只能是public abstract。省略的话 也是。
要点:
- 子类通过implements来实现接口中的规范
- 接口不能创建实例,但是可用于声明引用变量类型
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法之只能是public的。
- JDK1.7之前,接口中只能包含静态常量、抽象方法、不能有普通属性、构造方法、普通方法
- JDK1.8后,接口中包含普通静态方法
内部类的分类
在Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类
非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)
- 非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
- 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员
- 非静态内部类不能有静态方法、静态属性和静态初始化块
- 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例
成员变量访问要点:
- 内部类里方法的局部变量:变量名
- 内部类属性:this.变量名
- 外部类属性:外部类名.this.变量名
package com.junwei.oop;
public class TestInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
//创建内部类对象
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
class Outer{
private int age = 10;
public void testOuter(){
}
/**内部类*/
class Inner{
int age = 30;
public void show(){
int age = 20;
System.out.println("外部类的成员变量age:" + Outer.this.age);
System.out.println("方法内变量age:" + age);
System.out.println("内部类的成员变量age:" + this.age);
}
}
}
静态内部类
package com.junwei.oop;
public class TestInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
//创建内部类对象
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
class Outer{
private int age = 10;
public void testOuter(){
}
/**内部类*/
class Inner{
int age = 30;
public void show(){
int age = 20;
System.out.println("外部类的成员变量age:" + Outer.this.age);
System.out.println("方法内变量age:" + age);
System.out.println("内部类的成员变量age:" + this.age);
}
}
}
匿名内部类
package com.junwei.oop;
/**
* 匿名内部类
*/
public class TestAnonymousInnerClass {
public static void main(String[] args) {
TestAnonymousInnerClass.test(new AA() {
@Override
public void aa() {
System.out.println("你好匿名内部类!");
}
});
TestAnonymousInnerClass.test(()-> System.out.println("Lambda表达式实现匿名内部类!"));
}
public static void test(AA a){
a.aa();
}
}
interface AA{
void aa();
}
String基础
String类和常量池
在java的内存分析中,我们会经常听到关于“常量池”的描述,实际上常量池也分了以下三种:
全局字符串常量池(String Pool)
全局字符串常量池中存放的内容实在类加载完成后存到String pool中的,在每个JVM中只有一份,存放的是字符串常量的引用值(在堆中生成字符串对象实例)
class文件常量池(Class Constant Pool)
class常量池是在编译的时候每个class都有的,在编译阶段,存放的是常量(文本字符串、final常量等)和符号引用
运行时常量池(Runtime Constant Pool)
运行时常量池在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用保持一致。
通长比较字符串使用equals
String类常用方法
package com.junwei.oop;
public class TestString {
public static void main(String[] args) {
String s1 = " core Java ";
String s2 = "Core Java";
//提取下标为3的字符 从0开始
System.out.println(s1.charAt(3));
//字符串的长度 算上空格
System.out.println(s2.length());
//比较两个字符串是否相等
System.out.println(s1.equals(s2));
//比较两个字符串(忽略大小写)
System.out.println(s1.equalsIgnoreCase(s2));
//字符串s1中是否包含Java 返回首字符位置
System.out.println(s1.indexOf("Java"));
//将s1中的空格替换成&
String s = s1.replace(' ','&');
System.out.println(s);
//是否以core开头
System.out.println(s1.startsWith("core"));
//是否以Java结尾
System.out.println(s1.endsWith("Java"));
//提取字符串:从下标为4的开始到字符串结尾为止
System.out.println(s1.substring(4));
//提取字符串:下标[4,7)不包括7 前包后不包
System.out.println(s1.substring(4,7));
//转小写
System.out.println(s1.toLowerCase());
//转大写
System.out.println(s1.toUpperCase());
//去除首位空格
System.out.println(s1.trim());
}
}
数组的拷贝
arrayCopy
package com.junwei.array;
import org.jetbrains.annotations.Contract;
import org.junit.Test;
import java.util.Scanner;
public class TestArrayCopy {
static String[] s1 = {"aa","bb","cc","dd","ee"};
public static void main(String[] args) {
String[] s2 = new String[10];
//arrayCopy数组拷贝方法
// 要拷贝的数组,从哪开始拷贝,拷贝到哪个数组中,从新数组中的哪个位置开始,要拷贝的长度是多少
System.arraycopy(s1,2,s2,3,3);
for (String str : s2
) {
System.out.print(str+"\t");
}
System.out.println();
testDel();
System.out.println("----------------------");
while (true) {
testInsert();
System.out.println();
System.out.println("++++++++++++++++++++++++");
}
}
/**删除字符串指定元素的方法*/
public static String[] deleteElement(String[] str,int index){
System.arraycopy(str,index+1,str,index,str.length-index-1);
str[str.length-1] = null;
return str;
}
/**在数组指定位置插入元素*/
public static String[] insertElement(String[] strs, int index, String str){
//如果原数组已满 进行扩容
if (isFull(strs)){
String[] strings = new String[strs.length+strs.length];
System.arraycopy(strs,0,strings,0,strs.length);
System.arraycopy(strings,index,strings,index+1,strings.length-index-1);
strings[index] = str;
return strings;
}else {
System.arraycopy(strs,index,strs,index+1,strs.length-index-1);
strs[index] = str;
return strs;
}
}
/**判断数组是否以满*/
@Contract(pure = true)
public static boolean isFull(String[] strs){
for (int i = 0; i < strs.length; i++){
if (strs[i] == null){
return false;
}
}
return true;
}
@Test
public void test3(){
String str = null;
System.out.println(str == null);
}
public static void testInsert(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入要插入的元素:");
String str = sc.next();
System.out.println("请输入要插入元素的位置:");
int index = sc.nextInt();
String[] strings = insertElement(s1, index, str);
if (strings.length!=s1.length){
s1 = strings;
}
for(String s : strings){
System.out.print(s+"\t");
}
}
public static void testDel(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入要删除的元素下标");
int index = sc.nextInt();
String[] strings = deleteElement(s1, index);
for(String str : strings){
System.out.print(str+"\t");
}
}
@Test
public void test(){
//需求:将s1字符串cc删除
System.arraycopy(s1,3,s1,2,2);
s1[s1.length-1] = null;
for(String str : s1){
System.out.print(str+"\t");
}
}
/**数组的扩容
* 本质上是:先定义一个更大的数组,然后将原数组内容原封不动的拷贝到新数组中
* */
public static void extendRange(){
String[] s1 = {"aa","bb"};
String[] s2 = new String[s1.length+10];
System.arraycopy(s1,0,s2,0,s1.length);
}
}
Arrays工具类的使用
包含了排序、查找、填充、打印内容等常见操作
package com.junwei.array;
import java.util.Arrays;
public class TestArrays {
public static void main(String[] args) {
int[] nums = {2,4,1,3,8,4,5,23,12,31};
///输出
System.out.println(Arrays.toString(nums));
//排序
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
//查找 返回索引位置 如果查不到 返回 -1
System.out.println(Arrays.binarySearch(nums,3));
}
}
冒泡排序的基础算法
package com.junwei.array;
import java.util.Arrays;
/***冒泡排序及优化*/
public class TestBubbleSort {
public static void main(String[] args) {
int[] nums = {2,4,1,3,8,4,5,23,12,31};
int temp = 0;
for (int j = 0; j < nums.length-1; j++) {
//定义标志位
boolean flag = true;
for (int i = 0; i < nums.length-1-j; i++) {
//比较大小,换顺序
if (nums[i]>nums[i+1]){
temp = nums[i];
nums[i] = nums[i+1];
nums[i+1] = temp;
flag = false;
}
System.out.println(Arrays.toString(nums));
}
if (flag){
System.out.println("结束");
break;
}
System.out.println("---------------");
}
}
}
二分法查找(折半查找)
package com.junwei.array;
import java.util.Arrays;
/**
* 二分法查找
*/
public class TestBinarySearch {
public static void main(String[] args) {
int[] nums = {2,4,1,3,8,4,5,23,12,31};
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
int i = myBinarySearch(nums, 12);
System.out.println("位置:" + i);
}
public static int myBinarySearch(int[] nums, int value){
int low = 0;
int high = nums.length;
while (low <= high){
int mid = (low + high)/2;
if (value == nums[mid]){
return mid;
}
if (value > nums[mid]){
low = mid + 1;
}
if (value < nums[mid]){
high = mid - 1;
}
}
return -1;
}
}