泛型------数据结构

news2024/11/25 12:21:48

泛型

问题:下面是一个简单的顺序表,我们在这里面实现的一个顺序表,是存放的数据类型只有int类型,这就会很不通用,如果我们想什么样的类型的数据都想要放进去,就要把这个数组的类型设置成Object类型

能不能啥样的类型都可以存放呢?

class MyArraylist{
      private int[] arr1;
      private int usedsize;
      public MyArraylist()
      {
         this.arr1=new int[10];
      }
      public void add(int val)
      {
         this.arr1[usedSize]=val;
         usedSize++;
      }
      public int get(int pos)
      {
         return this.arr1[pos];
      }

   }

改成下面的代码之后,还是发现有问题:

1)这个代码太通用了,什么样类型的数据都可以进行存放不能指定元素,下面的代码里面的元素既可以存放整形,又可以存放String,完全就是一个大杂烩能不能只让他存放整型或者是字符串类型呢?

2)取出我们的Object顺序表中的元素,因为咱们返回的是Object类型,每一次取出数据的时候,还需要进行强制类型转换,这是很麻烦的;

package com.example.demo;

public class MyList {
    public Object[] array;
    public int usedSize;
    public MyList(){
        this.array=new Object[10];
        this.usedSize=0;
    }
    public void add(Object data){
        this.array[usedSize]=data;
        usedSize++;
    }
    public Object get(int index){
        return array[index];
    }
    public static void main(String[] args) {
        MyList list=new MyList();
//存放的时候,什么样子的数据类型都可以进行存放,就是一个大杂烩      
        list.add(1);
        list.add("abcde");
//虽然我知道1号位置的下标是一个String类型,但是取出元素的时候,还要进行强制类型转换        
        String str= (String) list.get(1);
        System.out.println(str);
    }
}

泛型和数组检查类型和存储的时间是不一样的,数组进行强制类型转换本质上并没有针对里面的所有元素进行强制类型转换

关于数组进行向下转型的问题:

为什么我们将自定义类型的数组强制转化成一个具体的类型就会发生报错呢?

1)实际上在JAVA里面,Object是所有class的根,当然数组也是一种class类型,因此比如说String[]和Object[]都是Object的子类类型

2)但是对于Object[]和String[]类型都是数组类型,他们之间并没有什么父子类关系,而是属于平级的关系,我们可能认为String[]类型是Object[]的子类类型,所以才会这么写,也就出现了classCastException异常,再说我感觉Object[]类型的数组转化成String[]类型的数组,编译器认为不安全,因为Object类型的数组不一定类型都是String类型的呀

我们现在想要做到下面几件事:

1)能不能指定我这个顺序表的类型,只能存放一种数据类型?传递啥类型就指定存什么类型,指定顺序表的类型

2)指定类型之后,是不是就只能存放指定类型的数据呢?

3)取出数据之后,可不可以不进行数据类型转换?或者是程序帮助我们自己来实现类型转换

 static class MyArraylist{
      private Object[] arr1;
      private int usedsize;
      public MyArraylist()
      {
         this.arr1=new Object[10];
      }
      public void add(Object val)
      {
         this.arr1[usedsize]=val;
         usedsize++;
      }
      public Object get(int pos)
      {
         return this.arr1[pos];
      }

   }

  public static void main(String[] args) {
  MyArraylist list=new MyArraylist();
    list.add(1);
    list.add("hello");
    String ret=(String)list.get(1);
  }

1)在指定类的后面写上<T>,它是代表当前的类是一个泛型类,此时的这个T就只是一个占位符而已,把类型参数化了,直接就是一个T类型的数组了,最终的结果是我们进行传递什么类型的数据,最终就存放什么类型的数据

2)private T[]=new T[10];--------private T[]=(T[])new Object[];

3)不能实例化一个泛型数组,比如说T[] array=new T[];

new一个泛型数组最好的方式就是通过反射

4)数组和泛型之间的一个重要区别就是说他们如何进行强制执行类型检查,具体来说,数组在运行的时候存储和检查类型信息,然而泛型是在编译的时候检查类型错误,并且在运行的时候没有类型信息,检查类型和存储的时机是不一样的

package com.example.demo;

public class TestDemo {
    public <T> T[] getArray(int size){
        T[] array=new T[size];
        return array;
    }
//如果上面的写法是正确的,在编译的时候就会变成这种类型,代码就会变成这样,于是在main方法就变成了这样
//就会出现下面的这种写法,因为new T[]或者是Object类型的数组,就会出现类似于下面这种Object类型的数组转化成某个具体类型的数组这样的错误
    public static Object[] getArray(int size){
        Object[] array=new Object[size];
        return array;
    }
    public static void main(String[] args) {
         String[] array=(String[]) getArray(10);
1)这里面的强制类型转换是错误的,因为只对数组整体进行了强制类型转换,部分元素并没有进行强制类型转换,就会抛出classCastException异常,如果说我们本身返回的数组就是一个String类型的数组,那么是不是就不会出现上面所说的情况呢?所以说我们具体在底层创建一个数组不是创建Object或者是T类型的数组,而是创建一个具体类型的数组,比如说尖括号里面是Integer,我们就创建一个Integer类型的数组,传递一个String,就创建一个String类型的数组
2)所以说这种写法是不正确的new T[]类型的数组,new Object
        //类型的数组都是不正确的
    }
}

class<E> classzz要传入一个具体的类型,创建一个具体的对应的类型的数组

泛型的意义:

1)存放数据的时候,在编译的时候会自动地对要放进去的类型进行检查是否和你指定的类型是否匹配,当取数据的时候,编译器会自动地对取出来的数据进行强制类型转换

2)泛型中<>里面的内容是不进行参与类型的组成的,泛型中尖括号的内容是不会参与类型的组成的,运行时期想要获取这些类型是根本获取不到的

3)泛型类型的参数,只能是包装类,而不能是简单类型

咱们内部的ArrayList使用泛型的时候也是new Object数组,但是他没有通过反射的方式来进行创建一个具体带有特定类型的数组,但是他的get方法,把他的单个元素强转成(E)(array[index]),不是整体数组强转,而是单个类型强转成E类型,也就是转换成了我们指定的类型;

泛型是怎么进行编译的?

1)我们先进行反编译一下:javap -c  类名,来进行查看一下对应的字节码文件,没有T类型,全部是Object类型

2)泛型是编译时期的一种机制

泛型这个概念只在编译时期起作用,在运行时期是没有泛型这个概念的,在编译时会把我们指定的类型被擦除为Object类型,编译器生成的字节码文件并不包含泛型的类型信息

package com.example.demo;

public class MyList<T>{
    public T[] array;
    public int usedSize;
    public MyList(){
        this.array=(T[])new Object[10];
        this.usedSize=0;
    }
    public void add(T data){
        this.array[usedSize]=data;
        usedSize++;
    }
    public T get(int index){
        return array[index];
    }

    public static void main(String[] args) {
     MyList<Integer> list=new MyList<>();
     //存放的时候,会自动堆存放进去的数据进行类型检查
        //只能存放整形数据 list.add("abc");
     list.add(1);
     list.add(2);
     //取出数据的时候,会自动根据我们类型进行强制类型转换
     int a=list.get(0);
     System.out.println(a);
    }
}
一:public class MyArray<E extends Number>{
}
这表示E可以是Number或者是Number的子类
1)MyArray<Integer> l1;//这是正常的,因为Integer是Number的子类
2)MyArray<String> l2;//这是错误的,因为String并不是Integer的子类
二:没有指定边界,默认就是Object,比如说class MyArray<T>{}

下面我们来写一个方法,来求数组中元素的最大值

class ALG<T>{
    public T GetMax(T[] array){
        T max=array[0];
        for(int i=1;i<array.length;i++){
 //这是引用类型的比较,max是T类型,array[i]也是引用类型,引用类型是不可以通过>=<来进行比较的
            if(array[i]>max)
            {
                max=array[i];
            }
        }
   return max;
    }

}

既然是引用类型,我们就要重写Compareable接口,重写compareTo方法来比较两个引用类型,但是我们发现上述这个代码,compareTo方法点不出来,因为程序不知道你这个类是否继承了Compareable接口?重写了CompareTo方法

class ALG<T extends Comparable<T>>
这种写法就表示此时这个T一定要实现Compareable接口,这是泛型的上界
package Demo;
class ALG<T extends Comparable<T>>{
    public T GetMax(T[] array){
        T max=array[0];
        for(int i=1;i<array.length;i++){
            //这是引用类型的比较,max是T类型,array[i]也是引用类型,引用类型是不可以通过>=<来进行比较的
            if(array[i].compareTo(max)>0)
            {
                max=array[i];
            }
        }
              return max;
    }
}
public class TestData {
    public static void main(String[] args) {
        ALG<String> avg=new ALG<>();
        String[] strings={"abcd","abc","ab","a"};
        int[] array={1,3,2,45,67,87};
        String str= avg.GetMax(strings);
        System.out.println(str);
    }
}

1)这时候会出现一个问题,咱们每一次调用findmax都要newALG()这样的对象吗,才可以通过这个对象的实例来进行调用findmax这样的方法,就显得太麻烦了

2)这个时候我们加上static关键字,不就可以保证通过类名来进行调用了吗?如果加上了static关键字之后,这个静态方法是不依赖于对象的,咱们的这个T参数是在new ALG中的尖括号进行传参的

class ALG<T extends Comparable<T>>{
    public static<T extends Comparable<T>> T GetMax(T[] array){
        T max=array[0];
        for(int i=1;i<array.length;i++){
            //这是引用类型的比较,max是T类型,array[i]也是引用类型,引用类型是不可以通过>=<来进行比较的
            if(array[i].compareTo(max)>0)
            {
                max=array[i];
            }
        }
   return max;
    }

}
这个时候就不需要进行new对象了,这就是咱们的一个静态的泛型方法
package Demo;
class ALG{
    public static<T extends Comparable<T>> T GetMax(T[] array){
        T max=array[0];
        for(int i=1;i<array.length;i++){
            //这是引用类型的比较,max是T类型,array[i]也是引用类型,引用类型是不可以通过>=<来进行比较的
            if(array[i].compareTo(max)>0)
            {
                max=array[i];
            }
        }
   return max;
    }

}
public class TestData {
    public static void main(String[] args) {
        Integer[] array={12,34,34,45,67};
       int max=ALG.<Integer>GetMax(array);
    }

}

理论上来说ArrayList<Integer> 不是ArrayList<Number>的父亲类型

ArrayList<Number>也不是ArrayList<Integer>的子类

通配符:

通配符是无法解决泛型无法谐变的问题的,谐变指的是Student如果是Person的子类,那么List<Student>也应该是List<Person>的子类,但是泛型是不支持这样的父子类关系的

1)泛型T是确定的类型,一旦你要是传了,我就定下来了,但是通配符可以说是更为灵活或者不稳定,更多地用于扩充参数的范围

2)或者我们可以这么理解:泛型T就像是一个变量,等待着你可以传输一个具体的类型,而通配符是一种规定,规定你可以传哪些参数

class AVL{
    public static<T> void print1(ArrayList<T> list){
        for(T x:list){//编译器一定知道当前传递过来的是一个T类型的数据
            System.out.println(x);
        }
    }
    public static void print2(ArrayList<?> list){
        for(Object x:list)//编译器不知道?是啥类型,具体的类型我不知道
        {
            System.out.println(x);
        }
    }
}

通配符的上界:

<? extends 上界>
<? extends Number>//可传入的参数类型是Number或者是Number的子类
举例:
public static void printAll(ArrayList<? extends Number > list>{}
//上面表示可以传入的类型是Number的子类的任意类型的ArrayList
下面都是正确的:
printAll(new ArrayList<Integer>());
printAll(new ArrayList<Double>());
printAll(new ArrayList<Number>());
下面搜是错误的
printAll(new ArrayList<String>());
printAll(new ArrayList<Object>());

假设现在有下面的关系:

Animal

Cat extends Animal

Dog extends Animal

根据上面的关系,写一个代码,打印一个存储了Animal或者Animal子类的list

代码1:

public static void print(ArrayList<Animal> list>{}

这样是不可以进行解决问题的,因为print的参数是List<Animal>,我们就不可以进行接收List<Cat> list

代码2:

public static<T extends Animal> void print3(List<T> list){

for(T animal:list){

System.out.println(animal);

     }

}

这时候T类型是Animal的子类或者是自己,该方法也是可以实现的,这里面的类型是一个确定的类型,编译器知道是什么类型

代码三:通配符来进行实现:

public static void print(List<? extends Animal> list>
{
 for(Animal x:list){
   System.out.println(x);//编译器此时不知道这是调用谁的ToString方法
发生了向上转型,不知道这个类型具体是啥类型,反正指定了上界,编译器就认为你传递过来的类一定是Animal或者是Animal的子类,如果没有这个通配符上界Animal这里面就应该写成Object了
   }
}

1)总结:ArrayList<? extends Number>是ArrayList<Integer>或者ArrayList<Double>的父类类型

2)ArrayList<?>是ArrayList<? extends Number>的父亲类型

通配符的上介是不适合用于写入对象的:

     ArrayList<Integer> list1=new ArrayList<>();
    list1.add(1);
    list1.add(2);
    ArrayList<Double>  list2=new ArrayList<>();
    List<?extends Number> list=list1;
      //list.add(1,9);//这里面是不适合进行写入数据的,适合于读数据,如果你进行存放的话,即可以进行存放整数,也可以存放浮点数这是不可以的,因为最最终引用的只有一种类型
      //list.add(2,10.9);
      Number number= list.get(1);//正确
      //Integer s1=list.get(0);这样的写法是错误的,因为不知道里面具体存放的是哪一种类型,万一存放的是Double类型呢

我们的通配符的上介适合读取数据,不适合写入数据,上面的list可以进行引用的对象有很多,编译器是无法确定你的具体的类型的,所以说编译器为了安全起见,此时只允许你进行读取

通配符的下界:

<? super 下界>
<? super Integer>这是代表可以进行传入的实参的类型是Integer或者是Integer的父类类型

假设有下面代码:

public static void printAll(ArrayList<? super Integer> list){
}
//下面表示传入的实参都是Integer的父类的任意类型的ArrayList
下面的调用都是正确的:
printAll(new ArrayList<Integer>());
printAll(new ArrayList<Number>());
printAll(new ArrayList<Object>());
下面的调用是编译错误的:
printAll(new ArrayList<String>);
printAll(new ArrayList<Double>);

咱们的ArrayList<? super Integer> 是ArrayList<Integer>的父类类型

ArrayList<?>是ArrayList<? super Integer>的父类类型

ArrayList<? super Person> list=new ArrayList<>();
//ArrayList<? super Person> list2=new ArrayList<Student>();这里面会出现报错,因为list2只能引用Person或者Person父类类型的list
list.add(new Person());//添加元素的时候,只要添加的元素是Person或者是Person的子类就可以了
list.add(new Student());
Person person=list.get(0)//父类引用引用子类对象,应该是对的呀????
Student s=list.get(0)//错误,因为Person的子类有很多,不一定就是Student
Object s=list.get(1);//正确

我们在进行添加元素的时候,我们知道list引用的对象肯定是Person或者是Person的父类的集合,此时我们可以确定此时能够储存的最小粒度比Person小就可以,你放的时候,放的都是Person或者Person的子类,但是你读取的时候,你能确定你读取的时候读取的是那一个子类吗?

回顾泛型(看懂代码)

什么是泛型?

我们说,一般的类型,只能引入或者使用具体的类型,要么是基本数据类型,要么是自己所自定义的类,如果我们想要编写可以应用于多种类型的代码,这种刻板的限制就会对代码的约束就会很大;泛型,就是适用很多很多种类型,就是对泛型作为了参数进行传递;

例如说,我们自定义一个数组,想要存放各种类型,把数组类型变成Object类型的数组即可,但是取元素的时候,要进行去进行类型转换;况且我们还可以什么类型都可以放,我们想要是实现只放字符串,只放整数,我想达到通用的效果;

全部变成Object类型的数组之后,虽然在这种情况下,当前数组的任何类型都是可以进行存放的,但是更多情况下,我们还是希望他只是可以同时持有一种数据类型,而不是同时持有这么多类型

所以说泛型的主要目的就是指定当前的容器,数据类型参数化,要放什么类型的对象,让编译器自己去进行类型检查

<T>表示是一个泛型类,T表示是一个占位符,我们是不可以实例化泛型数组的;

T[] arr1=T[](new Object[10]);

1)我们再进行编译的时候,会自动进行类型的检查;

2)在进行取元素的时候,编译器会自动进行进行强制类型的转换;

3)简单类型和基本数据类型是不可以作为泛型类型的参数的,必需使用包装类;

4)擦除机制:java的泛型机制(只存在编译的时候)是在编译级别实现的,编译器生成的字节码在运行期间并不包含泛型的基本类型信息,

5)在泛型中使用返回值是数组是,不能是T[],;接收的时候建议要用Object类型的数组去接收;

1)public class MyArray<E extends Number>那么此时E可以是Number(数字类)后者是Number的子类,此时类型只能是Integer,但是绝对不可以是String,他不是Number的子类;

2)public class MyArray<E extends Comparable<T>>表明我们传入的类型实现了这个接口;

写一个泛型类,求出数组的最大值 

class Test<T extends Comparable<T>>
{
  public T Findmax(T[] array)
  {    T max=array[0];
      for(int i=0;i<array.length;i++)
      {
          if(array[i].compareTo(max)>0)//不可以写成array[i]>max,所以实现Comparetor接口
              //自定义类型比较,要实现Compareable接口
          {
              max=array[i];
          }
      }
      return max;
  }
  public T[] DoubleArray(T[] array)
  {
      return array;
  }
}
class TestEnum {

    public static void main(String[] args) {
        Test<Integer> test=new Test<>();
        Integer[] array={12,23,13,24,89,80};
        int max= test.Findmax(array);
        System.out.println(max);
        Integer[] array1=test.DoubleArray(array);
        System.out.println(Arrays.toString(array1));
        Test<String> text=new Test<>();
        String[] arr1={"hello","world","lijiawei","lijiaxin"};
        System.out.println(text.Findmax(arr1));

    }
}

1)那么此时上面的代码也有不好的地方,每次我们想要求出我们进行自定义数组的最大值的是偶,必须先要new一个对象,创建一个实例,再去调用这里面的方法;

2)在方法名前面加上一个static关键字变成静态方法,未来在进行调用这个方法的时候,是不依赖于对象的,所以说他不知道T是啥

public static <T extends Comparable<T>> T Findmax(T[] array),变成这样之后,就不用new对象了;

直接通过类名.方法名即可;

3)我们未来再次进行调用时,直接写下面的代码

Integer[] array={12,1,3,5,8,9};
Integer max=Test.<Integer>Findmax(array);
  System.out.println(max);//是可以自动进行类型推导的

2.通配符的介绍(?在泛型中的使用,即为通配符)

****通配符是用来解决泛型无法进行协变的问题的,协变指的是如果Student如果是Person的子类,那么List<Student>也应该是List<Person>的子类,但是泛型是不支持这样的父子类关系的;

class Test{
    public static <T> void print1(ArrayList<T> list)
    {
        for(T t:list)
        {
            System.out.println(t);
        }
    }
    public static void print2(ArrayList<?> list)//通配符类型
    {
        for(Object x:list)
        {
            System.out.println(x);
        }
    }
}
class TestEnum {

    public static void main(String[] args) {
        ArrayList<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        Test.print1(list);
        Test.print2(list);
    }
}

 ******它只是使用于读取数据,而不是适用于写数据,因为此时List引用的子类对象有很多,编译器是无法知道一个具体的类型的,编译器为了安全起见,只允许进行读取;

但是当我们进行读取的时候,唯一可以确定的是他一定是number的子类

  ArrayList<Integer> list1=new ArrayList<>();
  ArrayList<Integer> list2=new ArrayList<>();
  List<?extends Number> list=list1;//这个list是list1和list2的父亲
  // list.add(32);这个代码是错误的
  //编译器此时就不知道了,它既可以引用list1,也可以引用List2,此时放的数据不知道是啥类型,所以就报错了
  Number i=list.get(0);
 //  Integer j=list.get(1);此时会发生报错,因为此时编译器不知道list在里面引用的是什么类型,所以我们统一用Number来进行接收

 支持写,不支持读,读必须用Object接收

class A{

}
class Person{

}
class Student extends Person{

}
class C extends Student{

}

class TestEnum{
    public static void main(String[] args) {
ArrayList<? super Person> list=new ArrayList<>();
list.add(new Person());
list.add(new Student());
list.add(new C());
//list.add(new A());此时会发生报错,里面只可以存放Person以及Person的子类
Object person1=list.get(0);

Student student=list.get(0)//产生报错

}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/116274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS中ArcMap栅格重采样操作与算法选择

本文介绍在ArcMap软件中&#xff0c;实现栅格图像重采样的具体操作&#xff0c;以及不同重采样方法的选择依据。 在文章Python中ArcPy实现栅格图像文件批量掩膜与批量重采样&#xff08;https://blog.csdn.net/zhebushibiaoshifu/article/details/124282764&#xff09;中&…

optimization问题的解决

目录 临界点critical point 基本介绍临界点两种情况的区分 g和H的举例介绍根据H区分Saddle Point和local minima 批次Batch batch大小的比较 时间的开销训练集和测试集的效果 训练集效果测试集效果 动量Momentum 一般的Gradient Descent带有动量的Gradient Descent 2021 -…

异步通信技术AJAX | 原理剖析、发送Ajax请求四步

目录 一&#xff1a;快速搞定AJAX&#xff08;第一篇&#xff09; 1、传统请求及缺点 2、AJAX请求原理剖析 3、AJAX概述 4、XMLHttpRequest对象 5、AJAX GET请求 6、AJAX GET请求提交数据 7、AJAX GET请求的缓存问题 8、AJAX POST请求及模拟表单提交数据 9、经典案例…

C语言基础--数组

文章目录一维数组一、一维数组的创建和初始化&#xff08;1&#xff09;一维数组的创建&#xff08;2&#xff09;一维数组的初始化1&#xff09;整形数组初始化2&#xff09;字符数组初始化3&#xff09;sizeof与strlen4&#xff09;总结二、一维数组的使用三、一维数组在内存…

基于C++实现(控制台)职工信息管理系统【100010060】

职工信息管理系统 一、实验内容 ​ 设计一个职工信息管理案例&#xff0c;实现不同类别职工的工资数据。职工的种类包括&#xff1a;正式职工和临时工。定义一个基本的职工类&#xff0c;基本信息包括&#xff1a;编号、姓名、性别、年龄、家庭住址、基本职务工资。派生出正式…

Quarkus实现第一个Hello World

Quarkus介绍 Quarkus 是一个为 Java 虚拟机&#xff08;JVM&#xff09;和原生编译而设计的全堆栈 Kubernetes 原生 Java 框架&#xff0c;用于专门针对容器优化 Java&#xff0c;并使其成为无服务器、云和 Kubernetes 环境的高效平台。 Quarkus 可与常用 Java 标准、框架和库…

php正则匹配反斜杠问题

php正则匹配反斜杠问题&#xff1a; 之前做了一道题&#xff0c;发现php中正则匹配反斜杠好像有点问题。 我们先看下面代码&#xff1a; <?php$cmd "\\";echo $cmd.PHP_EOL;if(preg_match("/\\\\|\\/",$cmd)) {echo "yes";} else {echo …

springdata-jpa-hibernate-03

springdata-jpa-hibernate-03 多表关联操作 首先加上这个lombok依赖,可以使代码更加简洁 一对一 account类 customerRepository接口 测试 一对多 message类 测试 多对一 在上面一对多的基础上加上这句代码就行 MessageRepository接口 测试&#xff1a; 多对多…

Mybatis-Plus快速入门

入门案例 MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提高效率开发方式基于MyBatis使用MyBatisPlus基于Spring使用MyBatisPlus基于SpringBoot使用MyBatisPlusSpringBoot整合MyBatis开发过程&#xff08;复习&#xff09;创建Spring…

DSP-Z变换

目录 Z变换的定义: Z变换的收敛域: 收敛域的定义: 收敛条件&#xff1a; Z变换收敛域的形状&#xff1a; 阿贝尔定理&#xff1a; 对于有限长序列的收敛域&#xff1a; Z变换的性质: 线性&#xff1a; 收敛域取交集&#xff1a; 时移&#xff1a; 指数相乘&#xf…

Java和Web前端哪个有发展前景?

Java和Web前端都是当今技术行业里的热门岗位&#xff0c;岗位招聘需求量大&#xff0c;人才竞争度高&#xff0c;同学们掌握这两个岗位里其中任何一个的相关主流技术&#xff0c;都可以找到一份不错的职位。下面请允许笔者做一个简要的分析阐述&#xff1a; 一、Web前端 Web前…

5 Redis

5.1 Redis 5.1.1 前言 前面使用到的mysql数据库会出现以下问题 由于用户量增大&#xff0c;请求数量也随之增大&#xff0c;数据压力过大 多台服务器之间数据不同步 多台服务器之间的锁&#xff0c;已经不存在互斥性了。 5.1.2 Redis 5.1.2.1 什么是Redis Redis&#x…

GO语言基础-05-循环和语句-select语句

文章目录1. 概述1.1 作用1.2 和switch比较1.3 执行过程2. 语法示例3. 完整示例1. 概述 1.1 作用 监听channel的数据流动 1.2 和switch比较 相同 开始的一个新的选择块&#xff0c;每个选择条件由case语句来描述。 不同 switch语句&#xff1a;可以选择任何使用相等比较的…

SpringCloud 协同开发方案

相比Springboot开发&#xff0c;SpringCloud开发要复杂的多&#xff0c;因为涉及服务的注册发现&#xff0c;多个微服务模块间的调用等。 最简单的解决方案是每个开发者都在本地启动一套完整的开发环境&#xff0c;包括网关、nacos等各个组成微服务的模块&#xff0c;如果系统…

Hive 学习Demo

背景介绍 陌陌作为聊天平台每天都会有大量用户在线&#xff0c;会出现大量的聊天数据&#xff0c;通过对聊天数据分析&#xff0c;可以更好的构建精确的用户画像&#xff0c;为用户提供更好的服务以及实现高ROI(投资回报率)的平台运营推广&#xff0c;给公司的发展决策提供精确…

智能网联汽车渗透率变化图显示预计

IDC 于 2020 年最新发布的《全球智能网 联汽车预测报告&#xff08;2020-2024&#xff09;》数据显示&#xff0c;尽管受新冠肺炎疫情冲击&#xff0c;2020 年全球智能网联汽车出货量预计较上一年下滑 10.6%&#xff0c;约为 4440 万辆&#xff0c;但到 2024 年全球智能网联汽车…

广播机制基础知识

广播机制 1.广播机制 1.1概述 1.1.1引入 1.广播的生活案例 记得以前读书的时候&#xff0c;每个班级都会有一个挂在墙上的大喇叭&#xff0c;用来广播一些通知&#xff0c;比如&#xff0c;开学要去搬书&#xff0c;广播&#xff1a; "每个班级找几个同学教务处拿书"…

商业智能BI与业务结构分析

做商业智能BI还必须熟悉行业和业务知识&#xff0c;不结合行业业务知识&#xff0c;商业智能BI的项目是很难落地的。商业智能BI的本质其实是企业的业务和管理思维的落地。企业的高层、业务部门的管理人员为什么要通过商业智能BI去看报表&#xff0c;他们看的是什么&#xff0c;…

深度学习-吴恩达(C3)结构化你的机器学习工程

结构化你的机器学习工程改变了深度学习的错误 比如你分割数据的方法&#xff0c;分割成train&#xff0c;development(dev)或叫valid&#xff0c;test&#xff0c;所以最好的实践方法是什么&#xff1f;了解更多端对端的深度学习&#xff0c;进而了解到你是否需要使用它&#…

Elasticsearch 核心技术(三):Kibana 安装、配置、运行(Windows 版)

❤️ 个人主页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;大数据核心技术从入门到精通 文章目录一、下载 Kibana二、安装 Kibana三、配置 Kibana1. 主机名2. 端口3. Elasticsea…