Java基础知识回顾(数组,函数,递归,对象,匿名内部类,接口,泛型)

”虽然我走得很慢,但我从不后退!“你好我是梦阳辰,快和我一起打卡学吧!

01.数组

1.为什么要数组?
如果没有数组,当保存很多数据时需要设置很多变量来存储,造成变量名过多,使得变成变得复杂。

如果有了数组,可以让相同类型的数据有序的保存起来,使编程变得简单起来。

2.当要求输出集合2中,跟集合1不同的数据时,我们该如何去解决呢?
我们知道,找到相同数据是很简单的,我们可以从这一点出发,设置标记,当遇到跟集合1相同的数据时,修改标记的值,并且跳出循环。再根据标记输出值。

for(int i:arrays1){
	boolean flag = false;//不相同
	for(int j:arrays2){
		if(i==j){
		flag = true;
		break;
	}
	if(!flag){
		System.out.print(j);
	}
}
	

如果采用以下方法则显得笨拙。

for(int i=0;i<N;i++){
            System.out.print(arrays1[i]+" ");
            for(int j=0;j<N;j++){
                if(arrays2[i]==arrays1[j]){//如果找到相同的值,直接跳过该值
                    break;
                }
                else if(arrays2[i]!=arrays1[j]&&j==N-1){
                    System.out.print(arrays2[i]+" ");
                }
            }

02.函数

1.函数的本质:
狭义:解决特定功能的一段代码。

广义的理解:函数是一个信息(或物品)加工的封闭的盒子。

2.命名规则
见名知意
变量的命名规则。

3.传递参数原则
最少原则
输入性/输出型参数。

4.返回结果
需要返回多个结果怎么办。

1.一个值代表多个含义(哥德堡猜想)。
2.封装成结构体或对象。
3.通过输出型参数返回。(引用)。

03.递归

(1)将n阶问题降阶为n-1阶问题。
(2)递归出口,初始条件。
(3)找到n阶和n-1阶的关系。

04.面向对象

1.对象:万物皆对象,对象是由静态的属性和动态的方法组成。
2.类:一组具有相同属性和行为对象的抽象事物。

例如:
3.消息:向某个对象发送请求。(手机来电)
4.方法:对象对收到请求的响应。(如:收到来电震动)

1.面向对象的基本特征

**抽象:**从一个具体的对象中提取一组数据,去除非本质和特性的东西,保留本质的,共性的。

**封装:**给对象一个边界,将内部信息隐藏,只保留对外的接口。比如遥控器,鼠标。

**继承:**允许后代直接使用前辈直接拥有的。继承是一种代码重用的方式,使代码更省略,更可靠。

2.类和对象的定义和方法

2.1类的定义:
Class 类名{
数据成员:-静态属性
成员函数: -动态行为
}

2.2对象的定义:
类名 对象名

this表示当前对象的引用!

2.3对于物体的抽象需要合理:

如定义三角形的类。
其属性应该是三个点,而非三条边来确定三角形。

2.4拷贝构造函数:
用已有的对象去创建一个相同的对象。

 Circle c1 = new Circle();
 Circle c2 = new Circle(c1);//用c1复制另一个对象。

//拷贝构造函数
public Circle( Circle c1){
	this.p=c1.p;//p为引用类型,p为Point类的对象的引用,保存的是地址。
	this.r=c1.r;
}

浅度拷贝:
上面那个例子,p为引用,将c1的引用地址赋值给新的对象c2,这会导致c1的p对应的对象发生改变,导致c2的p发生改变。

深度拷贝:
c1变化后c2不会发生改变。

2.5静态
静态成员修饰的成员与一般的成员有何区别呢?
一般的成员是每个对象有一份数据,而静态成员是属于类的,即所有对象所共享的。

一般成员的访问方式:对象名.成员名,而静态成员的访问方式:类名.成员名。

静态常量,静态成员变量,静态成员方法,静态代码块

静态变量一直存在,值不会动态的改变。

一般的成员都是通过构造函数去完成初始化(实例化对象时),而静态成员则是在加载类的时候(也就是实例化之前)初始化。

静态方法没有this

静态方法只能访问静态成员。

静态代码块在类加载的时候执行。

05.内部类和匿名内部类

1.内部类的作用?
内部类可以访问定义这个类的作用域中的私有属性。

内部类可以对其同包中的其它类隐藏。

内部类可以简洁的实现回调,不过现在lambda表达式在这方面做得很好。

内部类是指在一个类的内部定义的类

内部类可以自由访问外部类的所有成员

内部类可以作为成员类(在外部类中定义,和成员方法平行)和方法内部类(定义在外部类的成员方法里面)。

2.内部类的实例化:
Computer.Cpu cpu=new Computer().new Cpu();
System.out.println(cpu.getY());
当一个类离开另一个类而无法单独存在或者说没有意义的情况下,使用内部类是最合适的(如:CPU离开计算机类,单独存在就没有意义了)

3.匿名内部类
解决只用一次某个类的对象,使代码简洁的问题。只想创建某个类的一个对象,不需要为类指定名字。

public class InnerClass {
    /**
     * 动物接口
     */
    public interface Animal{
        public void eat();
        public void shot();
    }

    /**
     * 车类
     */
     public class Vehicle{
       
    }

    public static void main(String[] args) {
        /**
         * 匿名内部类
         */
        Animal dog = new Animal() {
            @Override
            public void eat() {
                System.out.println("吃狗粮!");
            }

            @Override
            public void shot() {
                System.out.println("汪汪汪");
            }
        };
        dog.eat();
        dog.shot();

        //内部类
       InnerClass.Vehicle car = new InnerClass().new Vehicle();
        
    }
}

06多态

多态:多态是同一个行为具有多个不同表现形式或形态的能力。

多态的意义:
(1)解决多种类型数据存放在同一容器问题。

(2)解决不同子类传递到同一个方法时,形参类型不同导致需要创建多个方法的问题。
而用形参设为父类,即可解决这个问题。

多态基于继承。

07.设置标记

设置标记,有时编程可以达到很好的效果。
下面为设计了exit标记来退出while循环。

 exit: while(true){//exit为标记
            System.out.println("请输入操作:");
            String s1 = scan.next();
            switch (s1){
                case "q":break exit;
                case "w":p1.move(0,1);break;//上移
                case "a":p1.move(-1,0);break;//左移
                case "s":p1.move(0,-1);break;//下移
                case "d":p1.move(1,0);break;//右移
            }
            p1.print();
        }

08.double数据类型比较大小

doulbe类型的数据比较大小不能用双等号。因为计算机的位数问题,double型数据又是不会那么精确,只是会无限接近于一个数。
而应该使用:Double的compare方法比较两个数据。

Double.compare(num1,num2)==0
Double.compare(num1,num2)>0
Double.compare(num1,num2)<0

09.抽象类和接口

1.抽象类规定了方法的名字和参数,虽无法创建对象,但是其具有上层规划的作用,其子类必须按要求实现其方法。

2.接口:属性为常量,方法为抽象方法。使用接口同样起到了统一规划的目的,便于使用和维护。

10.泛型

**泛型:**把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。

1.泛型的作用:

定义类或方法的时候不确定其类型,在使用的时候需要确定类型。解决了传类型问题。

泛型在集合中的作用:因为集合可以存储任何数据类型,在取出的时候,需要将其强制转换。而使用泛型规定了集合存储的类型,获取时不需要强制类型转换,可读性和稳定性增强。

2.类型参数:

1.将类型当作参数一样传递。

2.用法:<数据类型> 只能为引用数据类型。

ArrayList中的E称为类型参数变量。

ArrayList中的Integer称为实际类型参数

整个称为泛型类型。

3.泛型类

将泛型定义到类上,用户使用该类的时候,才把类型明确下来。这样就解决类强制类型转换的问题,避免了强制类型转换出错。
例子:

//队列类:
public class Queue<T>{//泛型类,用户在使用该类的时候才把类型确定下来
    private T[] data;//存放数据的区域
    private int capacity;//容量
    private int head;//头指针
    private int rear;//尾指针
    private int size;//实际数据个数
    private T result;//出队的值

    public Queue(int capacity) {
        this.capacity = capacity;
        data =(T[]) new Object[capacity];
        head = 0;
        rear = 0;
        size = 0;
    }

    /**
     * 数据入队
     * @param d 入队的数据
     * @return 入队是否成功
     */
    public boolean push(T d){
        if(size == capacity){
            return false;
        }
        data[rear]=d;
        rear = (rear+1)%capacity;//尾指针后移,并且可以循环回来
        size++;
        return true;
    }

    /**
     * 数据出队
     * @return 出队是否成功
     */
    public boolean pop(){
        if(size==0){
            return false;
        }
        this.result = this.data[head];
        head = (head+1)%capacity;
        size--;
        return true;
    }

    public T[] getData() {
        return data;
    }

    public void setData(T[] data) {
        this.data = data;
    }

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public int getHead() {
        return head;
    }

    public void setHead(int head) {
        this.head = head;
    }

    public int getRear() {
        return rear;
    }

    public void setRear(int rear) {
        this.rear = rear;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }
}

//测试类:
public class Test03{
    public static void main(String[] args) {
        Queue queue = new Queue(5);//objectl类型
        queue.push(2.2);
        queue.push(2);

        Queue<Integer> queue1 = new Queue<>(5);//泛型中的类型需为引用类型
        queue1.push(3);
        queue1.push(4);

        if(queue.pop()){
            System.out.println(queue.getResult());
        }
        if(queue1.pop()){
            System.out.println(queue1.getResult());
        }
    }
}

4.泛型方法

如果只想在某个方法上使用泛型,即用户只关心该方法,如果在类上定义就显得大材小用了。

public <T> void print(T t){
System.out.println(t);
}

//调用方法,传入的参数是什么类型,返回值就是什么类型。
对象.print("adf");
对象.print(123);
对象.print(2.22);

5.泛型类的子类

1.当子类明确了泛型类的类型参数变量

public interface Animal<T>{
	void shot(T,t);
}

pulic class dog implements Animal<String>{
	@Override
	public void shot(String s){
	System.out.println(s);
	}
}

2.当子类未明确泛型类的类型参数变量

public interface Animal<T>{
	void shot(T,t);
}

pulic class cat<T> implements Animal<T>{
	@Override
	public void shot(T s){
	System.out.println(s);
	}
}

测试:

public static void main(String[] args){
	//第一种情况
	Animal<String> i = new dog();
	i.shot("旺旺");
	//第二种情况
	Animal<String> i1 = new cat()<>;
	i1.shot("喵喵");
}

6.类型通配符


public void print(List list){


    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

当我们在遍历集合的时候,不知道集合中元素的类型,因为集合中的类型可以任意。直接遍历虽然可以实现,但是会出现警告。如何解决这个问题。如果我们知道每个元素的类型,我们可以一个个的强制转换,但是我们不清楚,这时我们可以使用通配符”?“解决这个问题。

public void print(List<?> list){


    for(int i=0;i<list.size();i++){
        
        System.out.println(list.get(i));
    
    }
}

**注意:**因为我们不知道元素的类型,所以我们不可以用对象含有类型的方法。
如:上面的例子我们不能使用list.add()方法。

7.通配符和泛型方法


    //使用通配符
    public static void print(List<?> list) {

    }

    //使用泛型方法
    public <T> void  print(List<T> t) {
        
    }

在使用上面这两个方法都是可以的解决上诉问题。
使用原则:

返回值是与参数之间有依赖关系的使用泛型方法。

如果没有依赖关系的,就使用通配符。

8.通配符上下限

1.通配符上限

List<? extends Number>

List集合只能是Number的子类或自身。

2.通配符下限

 <? super Type>

只能是Type的父类或自身。

泛型PECS原则总结

如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)

如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)

如果既要存又要取,那么就不要使用任何通配符。

埋怨只是一种懦弱的表现;努力,才是人生的态度。不安于现状,不甘于平庸,就可能在勇于进取的奋斗中奏响人生壮美的乐间。

在这里插入图片描述

以梦为马,不负韶华。
原文地址:https://www.cnblogs.com/huangjiahuan1314520/p/13710975.html