抽象类
类似于C++中的虚函数(virtual)
抽象方法
使用abstract修饰的方法,没有方法体,只有声明。定义是一种规范,就是要告诉子类必须要给抽象方法提供具体的实现。
抽象类
包含抽象方法的类就是抽象类。通过abstract方法定义规范,然后要求子类必须定义具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
package cn.yhq.oop;
public abstract class Animal {
//特点:1.没有实现。2.子类必须实现。
//作用:提示子类必须用这个方法。
abstract public void shout();
public void run(){
System.out.println("跑跑跑!");
}
public static void main(String[] args) {
Animal a = new Animal(); //这里不能被new
Animal b = new Dog();//但可以这样写
}
}
class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪");
}
}
使用要点
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
- 抽象类只能用来被继承。
- 抽象方法必须被子类实现
接口
idea中创建一个接口:右键点击New->Class->在class选项上选择Interface。
类似于C++中的.h文件,只有方法的声明,没有实现。
声明格式
[访问修饰符]interface 接口名 [extends 父接口1,父接口2...]{ //接口可以实现多继承
常量定义; //常量总是public static final修饰
方法定义;
}
注意:接口中不能定义变量,并且方法只能是public abstract
package cn.yhq.oop;
public class TestInterface {
public static void main(String[] args) {
Volant v = new Angel();//v不能调Honest方法
v.fly();
Honest h = new Angel();
h.helpOther();
}
}
interface Volant{
int FLY_HEIGHT = 100;
void fly();
}
interface Honest{
void helpOther();
}
class Angel implements Volant,Honest{
@Override
public void fly() {
System.out.println("飞飞飞");
}
@Override
public void helpOther() {
System.out.println("帮助他人");
} //实现类可以实现多个类接口
}
接口多继承
interface A{
void Amethod();
}
interface B{
void Bmethod();
}
interface C extends A,B{
void Cmethod();
}
class SubClass implements C{
@Override
public void Amethod() {
}
@Override
public void Bmethod() {
}
@Override
public void Cmethod() {
}
}
内部类的分类
在类中定义类。
Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类。成员内部类(可以使用private、default、protected、public任意进行修饰)。类文件中的表示:外部类$内部类.class。
a).非静态内部类:
package cn.yhq.oop;
public class TestInnerClass {
public static void main(String[] args) {
//创建内部类对象
Outer.Inner inner = new Outer().new Inner();//先创建外部类再创建内部类,注意:要new两次!!
inner.show();
}
}
class Outer{ //外部类不能使用内部类
private int age = 10;
public void tesyOuter(){
System.out.println("这是Outer的一个方法");
}
class Inner{//非静态内部类,只为Outer服务
//内部类中不能加静态这个属性
int age = 20;
public void show(){
int age = 30;
System.out.println("外部类的成员变量age:"+Outer.this.age);
System.out.println("内部类的成员变量age:"+this.age);
System.out.println("局部变量age:"+age);
}
}
}
b).静态内部类:
静态内部类可以看作外部类的一个静态成员。因此,外部类的方法中可以通过:“静态内部类.名字”的方式来访问静态内部类的静态成员,通过new静态内部类()访问静态内部类的实例。
public class TestStaticInnerClass {
public static void main(String[] args) {
Outer2.Inner2 inner = new Outer2.Inner2();
}
}//静态类中不能调用外部类的this
//同理,静态内部类中只能调用外类中的静态变量和方法
class Outer2{
static class Inner2{
}
}
c).匿名内部类的使用
适合那种只需要使用一次的类。比如:键盘监听操作等。
语法:
new 父类构造器(实参类表)或接口(){
//匿名内部类类体
}
例子:
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭程序");
System.exit(0);
}
});
//这个函数就是一个匿名内部类的例子,其中addWindowListener就是一个匿名内部类
class TestAnonymousInnerClass{
public static void test01(AA a){
a.aa();
}
}
interface AA{
void aa();
}
public static void main(String[] args) {
TestAnonymousInnerClass.test01(new AA() {
@Override
public void aa() {
System.out.println("匿名类调用");
}
});
}
d).局部内部类
定义在方法内部,作用域只限于本方法,称为局部内部类。
public class Test2{
public void show(){
//作用域仅限于该方法
class Inner{
public void fun(){
System.out.printIn("Helloworld");
}
}
new Inner().fun();
}
public static void main(){
new Test2().show();
}
}
String类
- String类又称不可变字符串序列
- String位于Java.lang包内,Java程序默认导入Java.lang包下的所有类
- Java没有内置的字符串类型,而是在标准Java类库中提供一个预定义的类String,每个用双括号括起来的字符串都是String类的一个实例。
demo:
String str10 = "YHQ";
String str11 = "YHQ";
String str12 = new String("YHQ");//这里创建了新的一个对象
System.out.println(str10 == str11);//带双引号的字符串,编译器会将其拼接起来,然后放到常量池里面
System.out.println(str12 == str11);//所以字符串比较使用equals()
String的比较使用equals
String常用的方法
数组深入
数组的拷贝
public static void main(String[] args) {
String[] s= {"a","b","c","d"};
String[] s2 = new String[10];
System.arraycopy(s,2,s2,6,3);
//从S的第2个位置拷贝到s2第6个位置,拷贝三个元素
//测试从数组中删除某个元素(本质还是数组的拷贝)
public static void testBasicCopy2(){
String[] s= {"a","b","c","d","e"};
// String[] s2 = new String[10];
System.arraycopy(s,3,s,3-1,s.length-3);
s[s.length -1] = null;
for (int i = 0;i<s.length;i++){
System.out.println(i+"--"+s[i]);
}
}
//数组扩容(先定义一个更大的数组,然后把原数组内容原封不动拷贝到新数组中)
public static void extendRange(){
String[] s1 = {"a","v","i"};
String[] s2 = new String[s1.length+10];
System.arraycopy(s1,0,s2,0,s1.length);//将s1中的元素拷贝到了s2
for (String temp:s2){
System.out.println(temp);
}
}
Arrays工具类
package cn.yhq.oop;
import java.util.Arrays;
public class TestArrays {
public static void main(String[] args) {
int[] a = {100,10,20,30,5};
//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,35));
}
}
二维数组
package cn.yhq.oop;
import java.util.Arrays;
public class TestTableArr {
//数组存储表格数据
public static void main(String[] args) {
Object[] emp1 = {100,"YHQ",19,"讲师","2003,1,13"};
Object[] emp2 = {101,"YOP",19,"讲师","2003,1,13"};
Object[] emp3 = {102,"YKI",19,"讲师","2003,1,13"};
Object[][] tableData = new Object[3][];
tableData[0] = emp1;
tableData[1] = emp2;
tableData[2] = emp3;
for (Object[] temp:tableData){
System.out.println(Arrays.toString(temp));
}
}
}
数组实例:二分法查找
先上自己写的代码,特点:冗余,空间占用率高
public static int[] halfFind(int[] arr,int goal){
int high = arr.length;
int low = 0;
int halfnum = ((high+low+1)/2)-1;
int times = 0;
while (true){
if (arr[halfnum]<goal){
low = halfnum;
halfnum = (low+high)/2;
times++;
}else if (arr[halfnum] > goal){
high = halfnum;
halfnum = (high+low)/2;
times++;
}
if (arr[halfnum] == goal){
System.out.println(goal+"在数组中的"+halfnum+"位置");
break;
}
if (times > 3){
System.out.println("查无此数"+"="+times);
break;
}
}
return arr;
}
思路就是定义三个索引,分别指向中间和两端,根据算法的特点去计算这三个点的移动,然后循环结束条件是:判断循环次数是否达到了时间复杂度最高的情况,使用一个计数器进行计数。
别人代码
public static int halfFind(int[] arr,int goal,int data){//data是用于方法重载的区别
int low = 0;
int high = arr.length-1;
data = 1;
while (low<=high){//由于low的自增性和high的自减性,始终会超过high
int mid = (low+high)/2;
if (goal == arr[mid]){
return mid;
}
if (goal>arr[mid]){
low = mid+1;
}
if (goal<arr[mid]){
high = mid-1;
}//基本实现其实是差不多的
}
return -1;
}