Unity11 - Java快速入门

C#基础上快速入门Java

目录

变量

  • Java中没有专门的无符号类型
  • 常量是final

运算符

C#

条件分支

  • if: 同C#
  • switch: 贯穿时可以加入逻辑语句, 其他同C#
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //C#
    //一个int i
    switch (i)
    {
    case 1: /*贯穿时case 1不允许有代码*/
    case 2:
    Console.WriteLine(i);
    break;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //Java
    //一个int i
    switch(i)
    {
    case 1: /*case 1中允许有自己单独的逻辑语句再贯穿*/
    i++;
    case 2:
    System.out.println(i);
    break;
    }

循环

  • whileC#
  • do {} while()C#
  • forC#
  • foreach: 使用同名for, 使用:替换in
    1
    2
    3
    4
    int[] arr = new int[]{1,2,3};
    for(int i : arr){
    System.out.println(i);
    }
  • break/continue: 同C#

数组

  • 声明方式多了一种:
    • int[] arr;
    • int arr[];

二维数组

  • Java的二维数组与C#的交错数组写法一致: int[][] arr

交错数组

  • int[][] arr = new int[n][]

Arrays类: 专门操作数组(java.util.Arrays)

  • 使用一个值填充数组: fill
    • Arrays.fill(数组,填充值)
    • Arrays.fill(数组,填充起始位置,填充最后位置,填充值)
  • 排序: sort
  • 复制数组: copyOf
    • Arrays.copyOf(被复制数组, 复制长度)
  • 复制数组特定范围: copyOfRange
    • Arrays.copyOfRange(被复制数组,起始位置,最后位置(不包括))
  • 二分法查询数组: binarySearch(使用前必须先排序)
    • Arrays.binarySearch(数组,元素)
    • Arrays.binarySearch(数组,起始搜索位置,最后搜索位置(不包括),元素)

函数

  • java函数没有refout
  • java函数的可变参数写法与C#不同
    1
    2
    3
    public static void test(String... strs){
    /*按String[]使用*/
    }
  • java函数没有默认参数的说法
  • java函数一般驼峰命名法(第一个小写,第二个单词开始大写)

面向对象

封装

  • 声明
    1
    2
    3
    4
    5
    6
    7
    8
    class 类名
    {
    //成员变量
    //成员方法
    //构造函数
    //finalize函数
    //静态函数
    }
  • C#的不同
    • 没有成员属性, 但有可以对成员变量自动生成get,set方法
    • 没有析构函数, 但有类似的finalize函数

      主动垃圾回收: System.gc();

    • 没有索引器
    • 没有运算符重载

继承

  • C#的相同
    • 类与类只能单继承
    • 万物之父Object
    • 遵循里氏替换
  • 继承关键字: extends替代C#中的:
  • Object类的一些方法
    • getClass(): 类似C#getType()
    • toString()
    • equals()

      equals比较两个对象的内容是否相等, ==比较两个对象的引用地址是否相同

  • instanceof判断类型, 类似C#中的is

    没有as, 只能用括号强转

  • final的作用
    • 禁止变量的修改 => 成为常量
    • 禁止函数的重写
    • 禁止类的继承

多态

  • Java中没有VOB
    • 没有virtual/override关键字, 重写时直接实现同名方法就可以覆盖父类方法, 使用super调用父类(类似base)
      1
      2
      3
      //C#里氏替换后默认调用父类方法
      Father s = new Son();
      s.Eat(); //父亲吃
      1
      2
      3
      //java里氏替换后直接调用子类方法(如果重写了)
      Father s = new Son();
      s.eat(); //子吃
    • java会自动补一个@override, 注释作用, 可有可无
  • 抽象类和抽象方法abstract: 同C#
  • 接口
    • 默认只能public
    • 字段只能是静态常量static final
    • 关键字implements, 用逗号,分隔多个接口
    • 没有显式实现接口: 多个接口有同名方法时, 重写的方法所有接口共享
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      //C#: 多个接口具有同名方法时, 必须显式实现
      public class SampleClass : IControl, ISurface
      {
      void IControl.Paint()
      {
      System.Console.WriteLine("IControl.Paint");
      }
      void ISurface.Paint()
      {
      System.Console.WriteLine("ISurface.Paint");
      }
      }
      //C#: 对象不可直接使用, 需要用接口装一次用对应接口使用
      SampleClass sample = new SampleClass();
      IControl control = sample;
      control.Paint();
      //C#: 或使用as
      (sample as IControl).Paint();

package: 类似C#中的命名空间namespace

包名规则

  • 多人完成, 版权归属发起者: indi.发起者名.项目名.模块名
  • 独立完成, 公开, 版权归属个人: pers.个人名.项目名.模块名
  • 独立完成, 非公开, 版权归属个人: priv.个人名.项目名.模块名
  • 团队研发, 版权归属团队: team.团队名.项目名.模块名
  • 公司研发, 版权归属公司: com.公司名.项目名.模块名

新建包

  • 包的本质是文件夹, class类是文件夹中的.java文件
  • 需要在文件夹内新建包, 对应的.java文件头部需要注明包名package 完整包名;

使用包

  • 关键字: import, 类似using
  • import的对象必须是特定的.java文件, 即必须引用到具体的class, 如果引用包中有多个.java文件则使用包名.*引入全部, 或仅引入特定几个
    • .java文件/class以大写字幕开头, 文件夹/package是小写字母

静态导入: 作为静态成员使用

1
2
3
4
5
6
7
8
9
10
//不导入包
System.out.println("不导入包");

//静态导入所有成员
import java.lang.System.*;
out.println("a");

//静态导入特定成员
import java.lang.System.out;
println("a");

内部类

非匿名内部类

  • 声明与C#相同, 使用不同: java内部类在外部的实例化必须依赖外部类对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //C#声明
    class Outer
    {
    class Inner
    {}
    }

    //C#使用
    Outer.Inner i = new Outer.Inner();
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //java声明
    class Outer
    {
    class Inner
    {}
    }

    //java使用
    Outer o = new Outer();
    Outer.Inner i = new o.Inner();
  • 外部类的所有成员(包括private)都可以直接供内部类使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //同名变量层级: 就近原则
    import java.lang.System.out;
    class Outer
    {
    private int i = ;

    class Inner
    {
    public int i = 2;

    public void Test()
    {
    int i = 3;
    println(i); //3
    println(this.i); //2
    println(Outer.this.i); //1
    }
    }
    }

匿名内部类(较少用)

  • 类似继承与重写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Outer
    {
    public void Test(){}
    }

    Outer o = new Outer(){
    @override
    public void Test()
    {
    /*自己的逻辑*/
    }
    };
    o.Test(); //自己的逻辑

字符串操作

String

  • 声明时直接赋值则存储在公共内存池, 使用new则主动划分一块区域
    1
    2
    3
    4
    5
    6
    7
    String s1 = "a";
    String s2 = "a";
    //以上两个变量指向同一个地址

    String s3 = new String("b");
    String s4 = new String("b");
    //以上两个变量指向两个区域
  • 拼接: 同C#, 生成新String
  • 常用方法
    • 判断相同: equals/equalsIgnoreCase

      ❗❗❗==判断引用地址, 因此只能用equals

    • 长度: length()

      ❗❗❗java中没有属性, 只有方法和变量(的gettersetter), 要获得对象的特定变量值, 要么使用对应的方法, 要么用对应的getter

    • 正反向查找: indexOf(String s)/lastIndexOf(String s), 无则-1
    • 指定位置字符: charAt(int i)
    • 取中间文本: substring(起始index,[结尾index(不包含)])
    • 去除首尾空格: trim()
    • 字符替换: replace(char 原, char 新)
    • 判断开头和结尾: startsWith(String s)/endsWith(String s)
    • 大小写转换: toLowerCase()/toUpperCase()
    • 字符串分割: split(String sign)
    • 字符串格式化: format(文本,数据...)
      • %tF: 年-月-日
      • %tD: 月/日/年
      • %tr: 时:分:秒 12h
      • %tT: 时:分:秒 24h
      • %tR: 时:分 24h

StringBuilder

  • 拼接: append(内容)
  • 插入: insert(位置,内容)
  • 删除: delete(起始位置, 结尾位置(不包含))
  • String: toString()

集合类

泛型

1
2
3
4
5
6
7
8
9
10
11
12
//泛型类的声明同`C#`一样, 调用时需要使用包装类而不是变量类型
public class Test<T>{}
Test<Integer> t = new Test<>();
//约束在<>中extends, 类或接口都是
public class Test2<T extends Test>{}
//泛型通配符?表示暂时不确定什么类型, 实例化时才确定, 可以extends
Test<?> t = null;
t = new String();

//泛型函数的声明需要写在访问修饰符后, 调用时直接调用
public<K> void Fun(K k){}
Fun(4);

ArrayListLinkedList(类似C#ListLinkedList)

  • ArrayListLinkedList都实现了List接口, List接口实现了Collection接口
  • ArrayListLinkedList具有相同的调用方法, 使用完全一致, 区别在于前者的本质是顺序存储的数组, 后者的本质是链式存储的链表
  • Collection接口方法
    • add()
    • remove()
    • clear()
    • isEmpty()
    • iterator(): 获取迭代器, 用于遍历
    • size()
    • contains()
    • toArray()将容器中的元素转为数组
  • List接口方法
    • get(int index)
    • set(int index, object obj)
  • ArrayListLinkedList使用
    • 声明: ArrayList<T> list = new ArrayList<>();
    • 增: list.add(T t);
    • 删: list.remove(int index);/list.remove(T t)/list.clear();
      • 可以传入int索引元素, 如果元素是int则只能传索引
      • 删除后后面的元素往前移动占位
    • 查: list.get(int index)/list.contains(T t)
    • 改: list.set(int index, T t)
    • 遍历: for/for:/Iterator
      1
      2
      3
      4
      Iterator<T t> it = list.iterator(); //Iterator泛型必须与list相同
      while(it.hasNext()){
      println(it.next());
      }

HashSetTreeSet

classDiagram
direction LR
class Collection{ <<interface>>}
class Set{ <<interface>>}
class HashSet
class SortedSet
class TreeSet
Collection <|.. Set:实现
Set <|.. HashSet:实现
Set <|.. SortedSet:实现
SortedSet <|-- TreeSet:继承
  • 相同点
    • 不允许重复元素, ArrayListLinkedList允许重复
    • 不能索引查改
  • 不同
    HashSet TreeSet
    底层数据结构 哈希表
    排列顺序 不一定有序 自动排序

    TreeSet的自动排序: 元素是数字时按大小排序, String按字符编码升序, 自定义类时需要实现Comparable接口重载排序方法

  • HashSetTreeSet使用
    • 声明: HashSet<T t> h = new HashSet<>()
    • 增: h.add(T t)
    • 删: h.remove(T t) 无法使用索引
    • 查: h.contains(T t)
    • 没有改
    • 遍历: for:/Iterator
  • TreeSet独有方法
    • 返回第一个/最后一个元素: first()/last()
    • 取出第一个/最后一个元素: pollFirst()/pollLast()
    • 取中间元素的集合: subSet(T tStart, T sEnd)(含左不含右)
    • 头部/尾部元素的集合: headSet(T t)/tailSet(T t)

HashMapTreeMap

classDiagram
direction LR
class Map{ <<interface>>}
class HashMap
class TreeMap
Map <|.. HashMap:实现
Map <|.. TreeMap:实现
  • Map方法
    • 添加: put(K key,V value)
    • 是否存在: containsKey(Object key)/containsValue(Object value)
    • 获取key的值: get(Object key) 没有key返回null
    • 所有key形成的Set: keySet()
    • 所有value形成的Collection: values()
    • 键值对对数: size()
    • 是否为空: isEmpty()
    • 移除by key: remove(Object key)
    • 清空: clear()
  • HashMapTreeMap相同点: 使用键值对存储数据, 方法基本相同
  • HashMapTreeMap不同
    HashMap TreeMap
    关于null 允许null键和null
    (但必须保证键的唯一性)
    不允许null
    数据存储顺序 内部会排序, 添加/删除/定位时效率较差
    数据结构 基于哈希表 基于树

    一般都使用HashMap, 除非需要排序时才使用TreeMap

  • HashMapTreeMap使用
    • 声明: HashMap<K k, V v> m = new HashMap<>()
    • 增/改: m.put(K k, V v)
    • 删: m.remove(K k)
    • 查: m.get(K k)/m.containsKey(K k)/m.containsValue(V v)

其他不常用内容做了解

异常处理: 基本同C#

1
2
3
try {}
catch (Exception ex) {}
finally {}

lambda

  • 基本结构: (参数)->{代码} 只有一行代码时省略{}
  • 函数式接口声明
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    interface ITest{ //一个空接口
    int Test(); //一个空函数
    }

    ITest t = ()->{ //对函数式接口中函数的lambda实现
    int i = 5;
    return i+1;
    }

    t.Test(); //调用

方法的引用和Function: 用函数装载函数式接口, 类似C#委托

  • 原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    public interface ITest{
    int Test();
    }
    public interface ITest2
    {
    public void Test fun();
    }
    public interface ITest3
    {
    public void Test fun(int i);
    }
    public interface ITest4<T>
    {
    public void Test fun(T t);
    }

    public class Test
    {
    public static int Add(){
    return 5;
    }
    public<T> static void FX(T t){}
    }

    //1.静态方法
    ITest t1 = Test::Add;
    t1.Test(); //等于Test.Add();

    //2.成员方法
    Test t = new Test();
    ITest t2 = t::Add();
    t2.Test(); //等于t.Add();

    //3.构造
    ITest2 t3 = Test::new;
    Test t = t3.fun(); //无参构造Test, 等于new Test()

    ITest3 t4 = Test::new;
    Test tt = t4.fun(5); //有参构造Test, 等于new Test(5)

    //4.泛型
    ITest4<Integer> t5 = Test::FX;
    t5.fun(55); //等于Test.FX(55);
  • 封装: Function<T,R>接口, T是参数,R是返回值, 调用方法apply
    1
    2
    Function<Integer,String> f = (i)->{ return (i+1).toString();};
    f.apply(5); //6

常用类库

  • 基本变量类型包装类: Integer,Boolean,Double,Character,Number
  • 较大数据BigInteger,BigDecimal
  • 数学计算类Math
  • 随机数类Random

Number: 所有数的父类

  • byteValue()byte形式返回数值
  • intValue/floatValue等等

BigInteger: 存储任意大小的整数

  • 使用add,subtract等方法运算, 不能用运算符运算

BigDecimal: 存储大浮点数

Math: 静态类

Date日期类, System系统类