今日学习两种经典算法冒泡排序和选择排序;静态static和常量final;以及抽象类与接口的知识
1. 冒泡排序:
- 规则:相邻的两个元素比较,符合条件的换位,每次比较总能得出大的或小的,因此每次循环的次数减一
- 代码示例:
for (int i = 0; i < nums.length - 1; i++) { //每轮找出最值,下轮就可以减一个元素比较 for (int j = 0; j < nums.length - i - 1; j++) { /* -i:让每次比较的元素减少,即去掉那个上一轮得出的最值(不用比的) -1:因为要和后面的元素比较,-1是防止数组元素下标越界 */ if (nums[j] > nums[j + 1]) {//从小到大 int num = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = num; } } }
2. 选择排序:
- 规则:用一个元素从头比到尾,就能找到最值,换位后一直比,知道全部排序好(类似穷举法)
- 代码示例:
for (int i = 0; i < nums.length - 1; i++) { //比到最后一轮,可以少比一次,因为当比到最后一轮时,它和之前的都比过了,可以减少一次 for (int j = i + 1; j < nums.length; j++) { //因为要和后面的每一位比较,之前的比过的不用比,所以起始值为外层循环的数+1 if (nums[i] > nums[j]) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } } }
3.static静态关键字
- static表示“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块。
- static的效果:被static修饰的成员变量和成员方法独立于该类的任何对象,也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就根据类名在运行时数据区(堆)的方法区内找到他们。也就是说,在这个类被加载时先加载这个类的静态的成员变量和静态成员方法,它的加载是在这个类创建对象之前的,所以static对象可以在它的任何对象创建之前访问,无需引用任何对象。
- 用法:static修饰后在其它类或方法中,可以用
类名.方法名
或者类名.属性名
直接操作,在本类中可以直接调用。 - static的好处:使用方便,随时调用,优化方法的复用性。
- static的缺点:占用静态空间,该空间无垃圾回收机制,除复用性极强的方法,尽量避免使用静态方法。
- 什么时候使用静态static好:在一个类被实例化为多个对象时,共用一个变量,此时使用静态变量会方便很多。
- 静态的优先级:静态代码块 > 构造代码块 > 构造方法
静态代码块:当程序加载到内存时,被执行,全执行一次(只要进入内存就不会再被执行)
构造代码块:可以给所有对象进行初始化
构造方法: 给对应的对象进行初始化
注意:在为创建对象时,静态方法只能调用静态变量;局部变量不能用静态来修饰。
4.变量的种类
- 类变量:1.由static修饰的变量称为静态变量或类变量。2.用静态修饰,那么该内容被所有对象所共享,此处说的共享,是指所有对象使用同一个变量,而非允许所有人使用,权限是由权限修饰符管理。
- 成员变量:1.成员变量定义在类中,在整个类中都可以被访问。2.成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。3.成员变量有默认初始化值。
- 局部变量:1.局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。2.局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。3.局部变量没有默认初始化值。
5.final关键字
- final关键字可以用来修饰类、方法、变量,各有不同。
- A:修饰类1.该类不能被继承2.类中方法不会被重写,因此默认都是final的3.用途是:当一个类不需要有子类,不必要被扩展,类实现的细节不允许被改变时,那么就设计成final的
- B:修饰方法1.这个方法可以被继承,但不能被重写2.用途是:一个类不允许子类重写该方法时,用final修饰3.好处是:可以防止继承他的子类修改该方法的意义和实现;更为高效,编译器在遇到调用final方法转入内嵌机制,提高了执行效率。
- C:修饰变量1.用final修饰后变为常量,包括静态变量,实例变量和局部变量三种。2.特点:可以先声明,不给初值,这叫做final空白,但是使用前必须赋值一次,并且用final修饰的变量只能赋值一次,一旦被赋值,将不能被改变。
- D:修饰参数:用final修饰参数时,可以读取该参数,但不能对其做出修改。
- final关键字不能用来修饰接口和抽象类,但是可以修饰其中的资源。
- final修饰属性时要注意:final绑定的时属性的值,基本数据类型绑定了数据本身,而引用数据类型绑定的是地址值,即final修饰的引用数据类型,不能更换指向对象实例,但还是可以修改对象实例里面的内容。
final Zi z1=new Zi(); //这样的话要修改z1的类型,修改不了,因为被final绑定了, //但是可以修改z1对象中的属性。 //因为这样是跳转了两次,第一次跳转到对象,对象的类型被final绑定了,修改不了 //第二次跳转到对象中的属性,这次跳转final绑定不了,所以可以修改其中的属性值
6.抽象类
- 抽象有什么用:当类里有的方法在描述事务时,不具体,无法准确的描述,这时,我们就可以用抽象来解决这个问题。
- 抽象的特点:抽象类必须用abstract关键字来修饰:
[访问权限修饰符] abstract class 类名{ 成员列表 }
抽象方法必须用abstract关键字来修饰,只有方法的的声明,没有方法的实现,没有方法体,并且定义在抽象类中。
[访问权限修饰符] abstract 返回值类型 方法名(参数列表);
- 抽象特点总结:
1.抽象方法没有方法体
2.抽象方法用abstract修饰
3.抽象方法只在抽象类中
4.抽象类,可以没有抽象方法
5.抽象类中,可以有抽象方法和普通方法
6.抽象类不能被创建对象,也就是不可以用new创建对象。抽象类通过其子类实例化(创建对象)
7.子类如果想当一个普通的类必须实现父类的所有抽象方法
8.子类如果不覆盖(实现)父类的抽象方法,那么子类就是 一个抽象类 - 抽象方法和普通方法的区别
1.抽象方法只有方法头,没有方法体。普通方法都有
2.抽象方法由abstract来修饰,普通方法没有
3.抽象方法必须活在抽象类中,普通方法既可以活在抽象类中也可以活在非抽象类中 - 抽象类和普通类的异同
1.相同点:抽象类和普通类都是用来描述事务的,都在内部定义了成员(方法和属性)。
2.不同点:普通类有足够信息来描述事务,抽身象类描述事务的信息有可能不够充足;普通类不能定义抽象方法,只能定义普通方法,抽象类中可以定义抽象方法,同时也可以定义普通方法,普通类可以被实例化,抽象类不可以被实例化(创建对象)。 - 抽象类还要注意的:
1.抽象类有构造方法,但是接口没有构造方法。
2.抽象类可以没有抽象方法,abstract不能和private、static、final共存
7.接口
- 接口的定义:当类中的方法都是抽象时,这个类就叫做接口;接口就是特殊的抽象类,即所有方法都是抽象方法的抽象类就是Java中的接口(interface);接口可以指定一个类必须做什么,而不是规定他如何去做。
- 接口如何创建
接口的关键字是:interface[访问权限修饰符] interface 接口名{ [public] [static] [final] 数据类型 变量名=初始化值; [public] [abstract] 返回值 方法();
接口中只放常量和方法的声明(抽象方法) - 接口中要注意的地方:接口中的成员修饰符是固定的,可以省略不写,但也默认是public的;接口中的常量都是静态的,必须赋初值,不能先声明后赋值,只能创建时直接赋初值。
- 类和接口的关系:类和接口是实现关系,由于接口不能被实例化,所以实现接口的子类必须重写接口中所有的抽象方法,这个子类才能创建对象,否则这个子类就是个抽象类
1.单实现
[访问权限修饰符] class 类名 implements 接口名{ 重写的接口中的方法(){} }
2.多实现
Java不支持多继承,但是将多继承机制改良成了多实现;即一个类可以实现多个接口,但要实现多个接口就必须把多个接口中的方法全部实现
[访问权限修饰符] class 类名 implements 接口名,接口名{ 重写的接口中的方法(){} }
多实现要实现所有接口的方法,但是多个接口有相同的方法,就只用重写一遍即可
- 接口和接口之间的关系
接口和接口之间是继承关系,而且可以多继承,因此接口的出现避免了单继承的局限性 - 类既可以继承也可以实现:
[访问权限修饰符] class 类名 extends 类 implements 接口名,接口名{ 重写的接口中的方法(){} }