Java基础复习笔记

164 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、Java的基本数据类型有哪些? 

        整数型:   byte,short,int,long。

        浮点型:  float,double。

        字符型: char。

        逻辑型:   boolean。

二、字符型char

        1.  字符常量常用单引号括起来的单个字符,如char a='a'。

        2. Java字符采用Unicode编码,每个字符占2个字节。因此可以用十六进制的编码形式表示。

          char c1='\u00061';

        3. Java语言中还允许使用''将其后的字符转变为其它的含义,如:  char c1='\n'; c1表示换行符。

        4. a对应的ascii码为97,A为65。

三、 整数类型

       1. Java各整数类型有固定的表数范围和字段长度,不受操作系统的具体影响,以保证Java程序的可移植性。

       2. Java整型常量的三种表现形式:

        十进制: 12,0,-200;

        八进制,要求以O开头,如:  O12。

        十六进制,要求以Ox开头,如Ox12。

        3. Long类型的数据需要在后面添加L,否则会报错。

        4. 字节范围:

          byte 1字节,-128~127 ;

         short 2字节,-2^15~2^15-1;

         int 4字节,-2^31~2^31-1;

         long 8字节:-2^63~2^63-1;

四、 浮点类型

      1.浮点类型默认的是double类型,如果声明为float类型,那么需要在变量后面添加f,如 float a=1.2f;

      2. float类型,4字节,小数点后7位,double 类型,8字节,小数点后15位,总结: 有效数字位数=整数位数+小数位数,7位以内的用float,15位以内的用double

      3. 在使用float或者double进行计算时,会出现精度丢失,通常使用BigDecimal进行更为准确的精度运算。

五、基本数据类型的转换

      1. boolean类型的变量不能转换为其他类型的数据。

      2. 整型变量可以自动转换,在运算的时候的转换规则如下:
1) byte,short,char之间不会相互转换。 

          2) byte,short,char ->int ->long->float->double,  容量小的会自动向容量大的转换。如: 

         int a=1;
Long b=2L;
Long result=a*b;  //运算时会将int类型的a转换为Long类型。

    3. 大类型向小类型转换为出现精度丢失、类型溢出,另外float强制转换为Long类型时,会直接舍弃小数部分。 

      精度丢失:
Float和Double提供了快速的运算,但是这2种类型的数据做二进制转换的时候,有些数字不能完全转换,造成精度丢失。

   
float a1=1.2f;
double b1=2.5;
double c=a1*b1;
System.out.println(c);

        打印结果:

     3.0000001192092896

    实际在开发中,我们对数据的要求较高的时候,那么尽量使用BigDecimal类型来定义小数。

      类型溢出: 
int a=1000000000;
int b=1000;
System.out.println(a*b);

      打印结果: -727379968   乘算的结果明显超出了Int类型的最大值。

六、为什么新建对象的时候需要重写equals方法的同时又需要重写hashCode()方法?

        答:   因为所有的类是Object的子类,每个类都会根据hash算法计算的哈希值来对应一个hashCode, 不同的类可能存在hashCode相同,但是如果hashCode不相同,那么2个对象肯定是不相同。 如果使用equals()方法相等的话,那么hascode的值一定相等,2个对象肯定相同,如果是hashCode()方法比较后的结果相等,那么equals()方法的结果有可能为true,也有可能会false,2个对象不一定相等,因为存在哈希表里的相同位置下的链表处的不同位置。

七、 final关键字的用法

      答:  修饰在类上该类不能被继承,修饰方法,在子类该父类的方法不能被重写, 修饰变量相当于是个常量,但不能被重新赋值, ,否则会报错。

            ​编辑

八、访问控制和继承

         

         答:需要牢记一点: 子类的访问权限需要大于或者等于父类。  明细规则如下: ;

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被继承。

九、 抽象类有哪些特性? 

       答:  1. 抽象类里的抽象方法必须使用Public或者protected访问权限来控制,不能使用private。

              2. 抽象类可以含有构造方法,因为抽象类可以使用匿名内部来来实例化。

              3.  抽象类与具体的类不同点在于,抽象类可以包含抽象方法,由其子类去具体的实现抽象方法,而且抽象类需要使用abstract 来进行修饰。

             例如:

package com.example.traditional;
/**
 *author:bingbing
 *日期:2020年7月13日
 *时间:下午10:06:41
 */

public abstract class Pizza {
	
	
     protected String name;
     
     public abstract void method();
     
     Pizza(){
    	 
    	 System.out.println("实例化抽象类!");
     }
	

}

          在Main方法里可以这样,只需要在匿名名内部类的形式来实现定义的抽象方法即可。

package com.example.traditional;
/**
 *author:bingbing
 *日期:2020年7月13日
 *时间:下午10:10:24
 */

public class Demo01 {
	
	
	public static void main(String[] args) {
		
		
		 Pizza pizza=new Pizza() {

			@Override
			public void method() {
				// TODO Auto-generated method stub
				
			}
			 
		 };
		
	}

}

十、静态内部类有哪些特性?        

        1.静态内部类可以在外部类的静态成员中访问或者实例化(非静态内部类不可以)---优势,例如单例模式的实例化。    


//使用静态内部类来创建实例
class Singleton {
	private static volatile Singleton instance;
	
	//私有构造器,防止被外部实例化
	private Singleton() {}
	
	//静态内部类,该类内有一个私有的静态属性
	private static class SingletonInstance {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	
	//提供一个公有的方法返回静态内部类创建的对象
	
	public static synchronized Singleton getInstance() {
		
		return SingletonInstance.INSTANCE;
	}
}

        2.静态内部类可以访问外部类的静态成员不可以访问非静态成员(非静态内部类可以访问类的静态和非静态成员)---限制

       ​编辑

      需要在a变量修改成static 才行,由此可以发现静态内部类只能访问外部类的静态成员属性和方法。 

        3. 静态内部类可以申明静态成员(非静态内部类则不可以申明静态成员)

package com.example.thread;

public class Demo04 {

	private static Demo04 demo04;

	static int a=0;

	static class Test{
		Demo04	demo04=new Demo04();
		static int b=1;
		void	test(){
			a=5;
		}
	} 

}

        4.在外部类外创建该外部类的内部静态类,不用依附于外部类的实例(而非静态内部类则需要依赖于外部类的实例),即访问的时候直接使用外部类.静态内部类类名  ,非静态内部类需要new一个实例出来,才能够访问。

十一、接口有哪些特性?     

      答:   1) 接口支持多继承。

             2) 接口声明的方法一般是没有body的,默认为public修饰,不能使用private和protected修饰。

             3) jdk1.8后,可以在接口里写入含有body的方法,但需要使用default 关键字修饰。

             4) 接口不能继承实体和抽象类。

public interface Test  implements A,B,C{


    public int test1();

    class a{

    }

    default int test(){
       return 0;
    }

}

十二、值传递和引用传递

      

          ​编辑

           答案:  A C D     考查的是引用传递和值传递,值传递是指在会将实参的变量进行拷贝一份,不会影响到实参的内容,引用传递的形参和实参实际指向的是内存中的同一个地址,但是参数地址不同,因此引用传递改变内容的话,也会改变实参的内容。

          以下i的打印结果为: 

package com.tedu.day05;
/**
 *author:bingbing
 *日期:2020年7月15日
 *时间:下午9:36:06
 */

public class Demo01 {
	
	
	public static void main(String[] args) {
		
		int i=0;
		aow(i++);
		System.out.println(i);
	}

	private static void aow(int i) {
		i+=2;
	}
	

}

   打印结果为:  1

考查值传递, 因为 aow方法的Int i为一个新的类型的Int,传参传的变量的一个拷贝,因此实际上i的值并没有发生改变。

十三、String 类型的学习

        1.  String str=new String("abc") ,创建了几个对象? 

        答:   1个或者2个,为什么是1个或者2个对象,那么我们可以先了解一下常量池的概念,JVM中 通过常量池来使字符串共享,那么使用常量池,可以避免字符串对象重复创建,比如常量池里面已经有了"abc",  那么String a="abc",就直接从常量池取出来。

      ****分析: ****String str=new String("abc"); 可以将这一行代码拆分为"abc"和new String(),String类的构造方法同时也是一个String 类型的数据, String original也为一个字符串,如果常量池里没有这个字符串,因此会先在常量池里创建一个对象, 同时也会通过new来新建一个对象,此情况下是创建了2个对象。

 public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
}

        如果常量池里已经存在了该字符串,那么就不会重复创建该对象,直接通过new来创建了一个对象。

        2. String,StringBuilder,StringBuffer有什么区别?

        String 是一个final类型,对值的修改是创建一个新的对象,如果常量池中存在,那么就不用重新创建,如果不存在那么就用重新创建对象,StringBuilder和StringBuffer对对象的修改可以多次,但不会创建新的对象。StringBuilder相比StringBuffer速度快,因为StringBuffer是线程安全的。

十四、 ==和equals的区别?

          基本类型用==比较的时候,比较的是值的内容,如果是引用类型比较的是地址。

          equals方法是Object类里的方法,用于比较地址,String类型重写了equals方法,比较的是内容值,包装类也重写了equals方法比较的也是值的内容。

          object: 

   public boolean equals(Object obj) {
        return (this == obj);
    }

          String: 

  public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

十五、重载、重写、向上造型、向下造型?

  答:  重载在一个类里面,方法名相同,方法的参数不同,返回类型可相同也可不同。

        重写在不同的类里面发生,子类重写父类的方法,调用的时候还是子类重写的方法。

        向上造型,指子类的对象赋值给父类的引用。

        向下造型,把指向子类对象的父类引用赋值给子类引用叫向下造型。

十六、什么是多态? 

      答:

    1. 多态是指同一个行为具有多个不同的表现形式或形态,多态其实就是用同一个接口去实现不同的目的,如打印机:

                   ​编辑

       2. 多态存在的条件是什么?

           继承、重写、父类引用指向子类对象。

  看如下例子: 

package com.example.day06;
/**
 *author:bingbing
 *日期:2020年7月19日
 *时间:上午10:33:25
 */

public abstract class  Animal {
	
	   abstract void eat();

}

猫:   

package com.example.day06;
/**
 *author:bingbing
 *日期:2020年7月19日
 *时间:上午10:34:25
 */

public class Cat extends Animal {

	@Override
	void eat() {
		System.out.println("猫吃鱼!");
		
	}

}

  狗:

package com.example.day06;
/**
 *author:bingbing
 *日期:2020年7月19日
 *时间:上午10:34:02
 */

public class Dog  extends Animal{
	
	

	@Override
	void eat() {
		System.out.println("狗吃骨头");
	}

}

测试类:
Cat 和Dog都是Animal的实例,因此可以使用intanceof 作判断: 

package com.example.day06;
/**
 *author:bingbing
 *日期:2020年7月19日
 *时间:上午10:35:21
 */

public class Test {
	
	
	public static void main(String[] args) {
		
		Cat c1=new Cat();
		show(c1);
		Dog d1=new Dog();
		show(d1);
		
		
	}
	
	
	public static void show(Animal a) {
		
		if(a instanceof Cat) {
			Cat c=(Cat)a;
			c.eat();
		}else if(a instanceof Dog) {
			Dog d=(Dog)a;
			d.eat();
		}
		
	}

}

打印结果:

猫吃鱼!
狗吃骨头

十七、静态绑定和动态绑定的区别是什么?

        答:   在java中,除了final、static、private修饰的方法和构造方法是静态绑定, 其他方式的方法均为动态绑定,在运行阶段绑定。区别有静态绑定是在编译阶段进行的,动态绑定是在运行阶段绑定的。

       如下代码输出结果为:

public class Main {
    public static void main(String[] args) {
        Father father = new Son();
        System.out.println(father.age);
        father.name();
        father.age();
    }
}
class Father{
    public int age = 50;
    public static void name(){
        System.out.println("Father name");
    }
    public void age(){
        System.out.println("Father age is " + age);
    }
}
class Son extends Father{
    public int age = 20;
    public static void name(){
        System.out.println("Son name");
    }
    @Override
    public void age(){
        System.out.println("Son age is " + age);
    }
}

打印结果:

          50

          Father name

          Son age is 20

       可以发现只有重写了的是动态绑定的,static修饰的方法时静态绑定的, fater.name() 方法仍然调用的是father的。