java基础学习

  • 目录

  • 变量类型
    • 整数
    • 浮点数
    • 字符类型
    • 布尔类型Boolean
  • 算术运算
    • 三目运算
    • 逻辑运算符
  • 面向对象
    • 类与对象
      • 匿名对象
      • 构造方法
    • 数组
      • 数组的方法引用操作
      • 关于数组的函数
    • 对象数组(!!!)
    • String类
      • 共享设计模式
      • 字符串一旦声明则不可改变
      • 字符串比较
      • 字符串查找
      • 字符串替换
      • 字符串截取
      • 字符串的拆分
      • 其他方法
    • this关键字
    • 引用传递
    • 代码块
      • 普通代码块
      • 构造块
      • 静态块
      • 同步代码块
  • lambda 表达式的语法


Java帮助文档:jdk/docs/api/index.html,内容为:

  • 类中成员的组成
  • 类中提供的构造方法
  • 类中所提供的的成员方法
  • 成员,构造方法,普通方法的详细说明

变量类型

整数

在java中默认的整数类型为int;

  • long
    要想在java中表示一个long类型的数字,尾部需要加l“L的小写”例如:
long num = 100l;
  • byte

byte占用一个字节的内存,在对byte进行赋值的时候例如

byte num = 100;

需要注意的特征:
虽然100是int类型数字,但是由于java的优化,所以这里不需要自己做强制类型转换。编译时也不会产生错误,这种情况只有在对byte进行直接赋值的时候才会出现,如果是间接赋值,则java并不会自己进行强制类型转换,需要自己声明。如果超过了byte的取值范围,则依然会以int类型为主。

浮点数

在java中默认的浮点数类型为double类型,(double类型为保存内容最广的数字类型)
- float
和long或者byte一样,在在需要最一个float进行赋值的时候,浮点数尾部需要加F来表示这个浮点数是float类型的数字,否则需要进行强制类型转换,而且由于float的取值范围比double小,所以在进行强制类型转化的时候数据值会有一点的差异。

float num = 100.0F;

字符类型

在java中字符编码使用十六进制Unicode编码
可以经过一些测试可以得到一些常用字符的编码:

'A'(65) ~ 'Z'(90)
'a'(97) ~ 'z'(122)
'0'(48) ~ '9'(57)

其中可以发现,大写字母和小写字母之间的编码差值为32,所以我们可以通过简单的计算来进行大小写转换,且其中大写字母的编码比小写字母的编码小。

布尔类型Boolean

boolearn只有两个值true和false

c/c++需要注意的是在java中不允许使用0或者1来表示true或者false

算术运算

三目运算

变量类型 变量 = 布尔表达式?满足词表达式的值:不满足次表达式的值;

逻辑运算符

  • 与(&或者&&)运算
&   //普通与,在进行运算的时候,算数不会进行短路运算,及当前半部分已经判断为假的时候依旧会运行后半部分
&&  //短路与,在进行运算的时候,如果前半部分判断为假的时候则后半部分的算不不会进行计算

面向对象

类与对象

匿名对象

没有栈指向的对象称为:匿名对象

例如:

class Book ()
{
    private String title = "hello ";
    public void setTitle()
    {
        System.out.println(title);
    }
    public Book (){};
}
public class test()
{
    public static void main ()
    {
        new Book().setTittle();
        //这里声明就位匿名对象
    }
}

根据上面的例子我们很容易法相,匿名对象只能使用一次,在使用一次之后,该对象就会被回收;

构造方法

  • 构造方法的名称与类名称相同
  • 和普通方法相比,没有返回值
  • 构造方法在类对象使用new实例化的时候被调用
  • 一个类之中至少有一个构造方法,如果没有明确定义构造方法,那么会自动生成一个无参的构造方法
  • 构造方法的核心为为了在我们给对象进行实例化的时候为对象中的属性进行初始化
  • 构造方法重载时,只要考虑参数的个数即可

需要特别注意的是:

class Book ()
{
    private String title = "hello ";
    public Book (){};
}

对于这样的构造方法,只有在执行构造方法之后title的值才为”hello “,在执行构造方法之前(即对象还没有进行构造的时候)title为对应数据类型的默认值(这里为null)。

数组

  • 首先需要了解的是数组为引用数据类型
  • 同时因为数组为引用数据类型,所以数组一定可以发生引用传递

声明并开辟数组:

数据类型 数组名称[] = new 数据类型[长度];

//等价于:

数据类型 []数组名称= new 数据类型[长度];
  • 数组初始化
//方法一(简化格式):
数据类型 数组名称[] = {值,值,值...};

//方法二(完整格式):
数据类型 数组名称[] = new 数据类型 [] {值,值,值...};

//二维数组初始化

数据类型 数组名称[][] = new 数据类型[行的个数][列的个数];

数据类型 数组名称[][] = new 数据类型[][]{{值,值},{值,值},{值,值}};

数组的方法引用操作

实例:

public class Main {
    public static void main(String[] args) {
        int data [] = new int [] {1,2,3};
        change(data);
        for(int i=0;iout.println(data[i]);
        }
    }
    public static void change(int temp []){
        for(int i=0;i2;
        }
    }
}

学过c的应该可以了解到,数组的引用传递相当于c中的指针,即形参改变,实参也会改变
总结来说,在java数组的引用传递中,方法中对数组的修改一定会影响到原始数据

关于数组的函数

数组名称.length //获取数组长度
数组名称.arraycopy(数组A,A的位置,数组B,数组B的位置,拷贝个数C)   //将数组A位置开始的C个数子,拷贝到数组b的位置
Array.sort(数组名称);   //数组排序

对象数组(!!!)

数组是引用类型,类也是引用类型,如果是对象数组则为一个引用类型里面嵌套了其他的引用类型。

之前使用的数组都属于基本数据类型的数组,但是所有引用类型的数据也可以定义数组,这样的数组我们成为对象数组

在实际应用中,数组用的很少,但是对象数组很常见,数组缺点,长度必须固定;
- 初始化

动态初始化:

类名称 对象数组名称[] = new 类名称[长度];

//也分布操作:

类名称 对象数组名称[] = null;    //声明对象数组
对象数组名称 = new 类名称[长度];   //开辟对象数组

静态初始化:

类名称 对象数组名称[] = new 类名称[] {实例化对象1,实例化对象2,.,.,.,.};

实例:

public class Main {
    public static void main(String[] args) {
        ff s [] = new ff[3];
        s[0] = new ff("aa",19);
        s[1] = new ff("bb",234);
        s[2] = new ff("cc",12);
        for(int i=0;i<3;i++){
            System.out.println(s[i].getinfo());
        }
    }
}
class ff
{
    private String name ;
    private int num;
    public ff(String name ,int num){
        this.name = name ;
        this.num = num;
    }
    public String getinfo(){
        return "名字:"+name+" 数字:"+num;
    }
}

String类

String类是一个字符串类,“ ”的内容就是就字符串内的内容。

  • 需要知道的是字符串常量就是String的匿名对象。

共享设计模式

在JVM底层有一个对象池(不一定只包存String对象),当代码之中使用了直接赋值的方式定义了一个String对象时,会将此字符串对象使用的匿名对象入池保存,而后如果还有其他String类对象也采用了直接赋值的方式,并且也设置了同样内容的时候,那么将不会开辟新的对内存空间,而是使用已有的对象进行引用的分配,从而继续使用。

例如:

public class Main {
    public static void main(String[] args) {
        String stra ="hello";
        String strb ="hello";
        String strc ="hello";
        System.out.println(stra==strb);
        System.out.println(stra==strc);
    }
}

输出结果为:

true
true

另外,如果是用了构造方法创建了一个String对象,那么他的内容不会保存在对象池中,因为是使用了关键字开辟的新内存。如果希望开辟的新内存也可以进行对象保存,那么采用String类定义的一个手工入池的方法:public String intern();

据说是面试题:

//直接赋值
String str = "字符串";
//这种方法只会开辟一个对内存空间,并且会自动保存在对象池中,以供下次重复使用。

//使用构造方法赋值
String str = new String("字符串");
//这种方法会开辟两个堆内存空间,其中一块内存会成为垃圾,另一块除非使用intern方法,否则不会保存在对象池中。

字符串一旦声明则不可改变

有人会说

public class Main {
    public static void main(String[] args) {
        String str = "hello ";
        str = str + "world ";
        str = str + "!!!!";
        System.out.println(str);
    }
} 

这样不是改变了吗?
实际上是这样的过程:

  1. 系统首先会声明一个”hello “匿名对象,然后将这个匿名对象赋值给str
  2. 系统会首先声明一个”world “匿名对象,然后进行加法,生成一个新的匿名对象,然后赋值给str,原来的”hello “匿名对象和”world “匿名对象则会变为垃圾对象被丢弃。
  3. 同理首先会声明一个”!!!!”匿名对象,然后进行字符串加法,得到的结果生成一个新的匿名对象,原来的“hello world ”匿名对象和”!!!!”匿名对象都会变成垃圾对象。

也就是说,在进行字符串加法,其实就是两个字符串生成一个新的字符串,然后再赋值给变量,而不是字符串发生了改变。即字符串对象内容的变化是利用了引用关系的变化实现的。每一次的变化都会产生垃圾空间。所以应该尽量减少这种操作。

字符串比较

String也可以使用==进行比较
例如:

String a = "aa";
String b = "bb";
System.out.println(a==b);

使用== 比较的是String 对象储存字符串的物理地址数值之间的比较,而与对象储存的字符串的内容无关;
要想比较string对象所储存的内容进行比较,需要使用String对象里面的方法实现

  • 使用String内的方法equals()
public boolean equals(String str);

//用法:

stra.equals(strb);

这个方法专门负责String内容之间的比较。

另外,字符串常量,也就是字符串的匿名对象也可以用这个方法。
如果是一个字符串和一个字符串常量进行比较,最好字符串常量调用方法,因为常量不会为空,所以不会出现指向异常。

"hello".equals("world");

字符串查找

public boolean contians(String s);  //判断制定的内容是否存在

public int indexOf(String s);   //查找制定字符串的位置,如果找到,则返回第一个找到的字符串的索引,如果没有找到则返回-1;
public int indexOf(String s, int fromIndex);    //从指定位置从前往后查询;

public int lastIndexOf(String str); //由后向前查询指定字符串的位置。
public int lastIndexOf(String str,int fromIndex)    //由后向前查询制定字符串位置,找不到返回-1;

public boolean starsWith(String prefix);    //判断是否以制定的字符串开头,如果是返回true,否则返回false。
public boolean startsWith(String prefix, int toffset)   //从制定位置开始判断是否以指定字符串开头。

public boolean endsWith (String suffix) //判断是否以指定的字符串结尾.

字符串替换

使用一个新的字符串替换掉就得字符串数据

public String replaceAll(String regex, String replacement)  //用新的字符串全部替换掉旧的字符串
public String replaceFirst(String regex, String replacement)    //替换首个满足条件的内容

实例:

public class Main {
    public static void main(String[] args){
        String str = "hello world !!!";
        String stra = str.replaceAll("l","_");
        String strb = str.replaceFirst("l","_");
        System.out.println(stra);
        System.out.println(strb);
    }
}

结果:

he__o wor_d !!!
he_lo world !!!

字符串截取

完整的字符串之中可以截取部分的子字符串的数据;

public String substring(int beginIndex) //从指定位置截取到结尾
//需要注意beginIndex的数值不能为负;
public String substring(int beginIndex ,int endIndex)   //截取部分子字符串的数据

代码实例:

public class Main {
    public static void main(String[] args){
        String str = "hello world !!!";
        String stra = str.substring(6);
        String strb = str.substring(0,5);
        System.out.println(stra);
        System.out.println(strb);
    }
}

运行结果:

world !!!
hello

字符串的拆分

将一个完整的字符串拆,按照指定内容拆分为字符串数组(对象数组)

public String[] split(String regex) //按照指定的字符串全部拆分
public String[] sqlit(String rege); //按照指定的字符串部分拆分,最后一个数组的长度是由就limit决定的。即:前面拆,后面不拆

实例:

public class Main {
    public static void main(String[] args){
        String str = "hello world !!!";
        String result [] = str.split(" ");
        for(int i=0;iout.println(result[i]);
        }
    }
}

结果:

hello
world
!!!
  • 当参数为split("")的时候""不是null,表示每一个字符串进行拆分
public class Main {
    public static void main(String[] args){
        String str = "hello world !!!";
        String result [] = str.split(" ",2);
        for(int i=0;iout.println(result[i]);
        }
    }
}

运行结果:

hello
world !!!
  • 即limit是用来控制字符串的长度

其他方法

在字符串里面不可以归类的方法。

public String concat(String str);   //字符串的连接,与“+”类似;
public String toLowerCase();    //转化为小写
public String toUpperCase();    //转化为大写
public String trim();   //去掉字符串左右两边的空格,中间空格保留
public int length();    //返回字符串的长度
public String intern();     //数据入池
public boolean isEmtpy();   //判断是否是空字符串,不是null,而是`“”`,即长度为零


this关键字

  • 功能1:调用别列中的变量

在java的程序里以“{}”为界限,如果没有加入任何的限制,重名变量指的都是最近的“{}”内的变量名称。当在这种情况下,为了可以明确的找到要访问的变量属于类中的属性的时候,我们需要在变量名称前加this
例如:

class ff
{
    private String ss;  //位置1
    public void ff (String ss){
        //这里的this.ss指的是位置1出的ss,而后面的ss指的是构造函数里面传过来的ss
        this.ss = ss;
    }
}

建议在java开发中,所有使用的类中的变量都要加上this.

  • 功能2:调用本类中的方法
class ff
{
    public void print()
    {
        System.out.println("");
    }
    public void ff (String ss){
        this.print();
    }
}

虽然上例中的this加过着不加都可以,但是在这里建议都加上;

  • this调用本类的构造方法

this还可以在一个类中调用本类的构造方法,形式如下:

this();
this(参数);
this(参数,参数);
...

这种调用常用在构造方法之间的互相调用,在特定情况下,使用好的话可以大大减小重复代码的出现;

需要注意的是:

在使用this()调用构造方法的时候代码只能放在u早方法的首行。

在使用this()在构造方法之间相互调用的的时候,一定要保留调用出口。

  • this 表示当前对象
    在一个类里面this (不加任何参数和括号)这个时候this表示调用这个类的对象,即表示当前对象;
class ff
{
    public void print()
    {
    //这个时候this表示的是当前对象,即输出的是调用这个方法的对象的物理内存地址
    System.out.println(this);
    }
}

引用传递

这里使用三个实例来说明:

  • 实例1:
public class Main {
    public static void main(String[] args) {
        ff abc = new ff(30);
        fun(abc);//传值调用
        System.out.println(abc.getff());
    }
     public static void fun (ff msg)
    {
        msg.setff(100);
    }
}
class ff
{
    private int num =10;
    public ff(int num)
    {
        this.num = num ;
    }
    public void setff(int num)
    {
        this.num = num ;
    }
    public int getff()
    {
        return num;
    }
}

猜猜这个程序的结果会是什么?
注意num的类型为基本型,(基本型和引用型的最大差别就是基本型没有内存的关系匹配)

正确答案是:

100

可以思考一下为什么?

  • 实例2:
public class Main {
    public static void main(String[] args) {
        String str = "hello";
        fun(str);
        System.out.println(str);
    }
     public static void fun (String ss)
    {
        ss="world";
    }
}

这个结果会是什么呢?

正确答案是:

hello

这里需要注意的是,String(引用类型)类型一但申明,则不可改变,对象内容的改变依靠的是引用地址的改变。

也就是说一开的时候,ss指向的堆内存为str指向的堆内存,但是当执行ss="world";之后ss指向的是"world" 的内存地址,而str指向的内存地址是没有改变的。

  • 实例3:
public class Main {
    public static void main(String[] args) {
        ff str = new ff("hello");
        fun(str);
        System.out.println(str.getff());
    }
     public static void fun (ff ss)
    {
        ss.setff("world");
    }
}
class ff
{
    String info = "abcd";
    public ff(String info){
        this.info = info ;
    }
    public void setff(String info ){
        this.info = info ;
    }
    public String getff( ){
        return this.info ;
    }
}

这个答案为:

world
  • 总结

虽然String属于类,属于引用类型,但是由于其内容不可改变的特点,很多时候把String当成基本数据类型是不可以的,也就是说,每一个String变量只能够保存一个数据。

  • 一个引用实例
public class Main {
    public static void main(String[] args) {
        //生成一个人的对象
        Member m = new Member(1, "ss");
        //生成一个车的对象
        Car c = new Car(0, "che");
        //把车的信息赋值给人
        m.setCar(c);
        //在车的信息里记录拥有它的人的信息
        c.setMember(m);
        //找到这个人车的信息
        m.getCar().getCar();
        //找到拥有这个车的人的信息
        c.getMember().getMemder();

    }
}
class Member
{ 
    //一个人的信息
    private int num ;
    private String name ;
    //一个人有一个车
    private Car car;
    public Member() {
    }

    public Member(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public void setCar(Car car){
        this.car = car;
    }
    //如果car为null,则代表没有车,如果有,那么赋值
    public Car getCar(){
        return this.car;
    }

    //获取这个人的信息
    public void getMemder (){
        System.out.println("这个人的编号:"+this.num + "是 "+ this.name);
    }
}
class Car
{
    //一个车的信息
    private int mid;
    private String name ;
    //一个车值属于一个人
    private Member member;
    public Car() {
    }

    public Car(int mid, String name) {
        this.mid = mid;
        this.name = name;
    }
    //给车赋予它所属人的信息
    public void setMember (Member member){
        this.member = member;
    }
    public Member getMember(){
        return this.member;
    }

    //获取车的信息
    public void getCar (){
        System.out.println("车的信息:"+ this.mid +"  "+this.name);
    }
}

代码块

代码块即使用大括号`{}`定义的一段程序代码,根据定义的位置和声明的关键字不同可以分为四类:**普通代码块**、**构造块**、**静态块**、**同步代码块**

普通代码块

定义在方法中的代码块。
public 方法名称(){
    {//这就是普通代码块
        int x;//相对于下面的代码块,这里的变量x为局部变量
    }
    int x;
}

构造块

定义在类里面的代码块(一个类中可以有多个构造快),在实例化的时候需要先从上往下一次执行代码块然后才开始执行构造方法
class 类名称 {
    { //构造块1

    }

    public 类名称(){
    }

    {  //构造块2

    }

}

在这里执行顺序为:构造快1==》构造快2==》构造方法。

  • 可以进行一些简单的逻辑操作

静态块

用static关键字定义的代码块,**静态块优于构造块**,且不管产生多少个实例化对象,只执行一遍,可以用于初始化static属性。

静态块可以分为两类:
- 在非主类中定义的静态块;

class 类名称 {
    { //构造块1

    }

    public 类名称(){
    }

    static{//静态块

    }

}
- 在主类中定义的静态块。

当静态块在主类中定义的时候,静态块将优先于主方法执行

public class 类名称(){
    static{
    }
    public static void main (String args[]){
    }
}

同步代码块

稍后更新~~~

lambda 表达式的语法

lambda 表达式是一个可传递的代码块,可以在以后执行一次货多次。

  • 如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,吧这些代码放在{}中,并包含显式的return 语句。
(String first, String second) ->
{   
    if(first.length()return -1;
    else if(first.length() > second.length()) return 1;
    else return 0;
}
  • 即使lambda表达式没有参数,仍要提供空括号,就像无参数方法一样:
() -> { for (int i=100; i>=0; i--) System.out.println(i);}
  • 如果可以推导出一个lambda表达式的参数类型,则可以忽略其类型
Comparator  comp
 = (first, second)
     -> first.length() - second.length();
  • 如果方法只有一个参数,而且这个参数的类型可以推到得出,那么甚至可以省略小括号
ActionListener listener= event ->
    System.out.println("The time is " + new Date());
  • 无需指定lambda表达式的返回类型。lambda表达式的返回类型总是会由上下文推到得出
(String first, String second) -> first.length() - second.length();

你可能感兴趣的:(java学习)