java基础知识

4.1 基本概念

1.java语言是由C++语言改进并重新设计而来的。
2.java语言中的方法必定隶属于某一类(对象),调用方法与过程或函数相同。
3.main()方法还有其他可用的定义形式:

1)public 与 static没有先后顺序关系   static public void main(String[] args)
2)也可以把main方法定义为final   public static final void main(String[] args)
3)也可以用synchronized 来修饰main方法   public static synchronized void main(String[] args)
不管哪种定义方法,都必须保证main()方法的返回值为void,并且有public 和satatic关键字修饰。同时由于main()方法是程序的入口方法,因此不能用abstract关键字来修饰
同一个.java文件中可以有多个mian方法,但是只有与文件名相同的用public 修饰的类中的main方法才可以作为整个程序的入口方法。

4.如何实现在main方法执行前输出”Hello World”

public static void main(String[] args) {
        System.out.println("Test main");
    }
static{
    System.out.println("Hello World!");
}
在java语言中,由于静态块在类被加载时就会被调用,因此可以在main方法被执行前,利用静态代码块实现输出Hello World.

5.java程序的初始化顺序是咋样的

package hello;

public class Base {
    static{
        System.out.println("Base static block");
    }

    {
        System.out.println("Base block");
    }

    public Base(){
        System.out.println("Base constructor");
    }
}


-----------------------------------------------------------

package hello;

public class Derived extends Base {
    static{
        System.out.println("Derived static block");
    }

    {
        System.out.println("Derived block");
    }

    public Derived(){
        System.out.println("Derived constructor");
    }

    public static void main(String[] args) {
        new Derived();
    }
}


-----------------------------------------------------------
运行结果:
Base static block
Derived static block
Base block
Base constructor
Derived block
Derived constructor
----------------------------------------------------------
java程序初始化工作可以在许多不同的代码块中来完成,他们执行的顺序如下:
父类静态变量,父类静态代码块,子类静态变量,子类静态代码块
父类非静态变量,父类非静态代码块,父类构造函数,子类非静态变量,子类非静态代码块,子类构造函数。

6.java中的作用域有哪些:

在java中变量的类型主要有3种:
成员变量:类的成员变量的作用范围与类的实例化对象的作用范围相同。类被实例化时创建
静态变量/全局变量:被stataic修饰的成员变量,类被加载时创建
局部变量:作用域与可见性在它所在的{}内。

作用域的对比:

public :表明该成员变量或方法对所有类或对象都是可见的
private:表明该成员变量或方法是私有的,只有当前类对去有访问权限
protected:表明该成员变量或方法对自己及其子类是可见的。其他包不可见
default:表明该成员变量和或方法对自己和同包类可见,若父类和子类位于同包类,则子类对父类的default成员变量或方法有访问权限。
注意:
这些修饰符只能用来修饰成员变量,不用用来修饰局部变量。
private 与 protected不能用来修饰类(只有public,abstract或final能用来修饰类)
所以:当超类的实例方法或类方法为private时,是不能被子类调用的,同理,当其他类的实例方法为private,也不能被直接调用。

7.一个.java文件可以定义多个 类

一个java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名必须与文件名相同。
若这个类中没有public的类,则文件名随便是一个类的名字就可。需要注意的是:当用javac指令编译这个.java文件时,它会给每一个类生成一个对应的.class文件。

8.什么是构造函数:

构造函数用来在对象实例化时初始化对象的成员变量。
特点:
1)构造函数必须与类名相同,并且不能有返回值(返回值也不能为void)
2)每个类可以有多个构造函数,如果开发人员没有提供构造函数,则编译器在把源代码编译为字节码的过程中会提供一个没有参数默认的构造函数,但是该构造函数不会执行任何代码。如果开发人员提供了构造函数,那么编译器就不再会创建默认的构造函数了。
3)构造函数可以有0,1,2个参数
4)构造函数总是伴随着new操作一起调用,且不能由程序的编写者直接调用,必须由系统调用。构造函数在对象实例化时会被自动调用,且只运行一次。
5)构造函数不能被继承,因此不能被覆盖,但是可以被重载。
6)子类可以通过super关键字来显示的调用父类的构造函数,当父类没有提供无参数的构造函数时,子类的构造函数中必须显示的调用父类的构造函数。。
7)当父类和子类都没有定义构造函数的时候,编译器会为父类和子类生成一个默认的无参数的构造函数。此外默认的构造函数的修饰符只和当前类的修饰符有关。

普通方法是否可以与构造函数有相同的方法名?

package hello;

public class Test {

    public Test(){
        System.out.println("construct");
    }

    public void Test(){
        System.out.println("call Test");
    }

    public static void main(String[] args) {
        Test a = new Test();//调用构造方法
        a.Test();//调用普通方法
    }

}

----------------------------------------------------------------
运行结果:
construct
call Test

9.为什么java中有些接口没有任何方法?

接口中所有的方法都是抽象的。
接口中成员的作用域修饰符都是public,接口中的常亮值默认使用public static final修饰。
没有任何方法的接口又叫标识接口,仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型。例如:Cloneable,Serializable.在使用时会经常使用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。

例如

要开发一款游戏,游戏里面一个任务专门负责出去收集有用的材料,假设这个人物只收集矿石和武器,而不会收集垃圾。下面通过标识接口来实现这个功能。
package hello;

public interface Stuff {}

//矿石
interface Ore extends Stuff{}

//武器
interface Weapon extends Stuff{}

//垃圾
interface Rubbish extends Stuff{}

------------------------------------------------------------------
package hello;

import java.util.ArrayList;

public class Test {
    public static ArrayList collectStuff(Stuff[] s){
        ArrayList al = new ArrayList<>();
        for (int i = 0; i < s.length; i++) {
            if(!(s[i] instanceof Rubbish)){
                al.add(s[i]);
            }
        }
        return al;
    }

    public static void main(String[] args) {
        Stuff[] s = {new Gold(),new Copper(),new Gun(),new Grenade(),new Stone()};
        ArrayList al = collectStuff(s);
        System.out.println("The usefull Stuff collected is:");
        for (int i = 0; i < al.size(); i++) {
            System.out.println(al.get(i));
        }
    }
}

//金矿
class Gold implements Ore{
    public String toString() {
        return "Gold";
    }
}

//铜矿
class Copper implements Ore{
    public String toString() {
        return "Copper";
    }
}

//枪
class Gun implements Weapon{
    public String toString() {
        return "Gun";
    }
}

//榴弹
class Grenade implements Ore{
    public String toString() {
        return "Grenade";
    }
}

//石头垃圾
class Stone implements Rubbish{
    public String toString() {
        return "Stone";
    }
}

在上例中,设计了三个接口,Ore,Weapon,和Rubbish分别代表矿石,武器和垃圾,只有是实现Ore,Weapon的类,会被认为是有用的类,只要是实现Rubbish的类,会被认为是垃圾,例如stone,因此不会被收集。

不能用来修饰接口interface的有:private,protected,static

10.java中clone方法有什么作用
由于java取消了指针的概念,因此开发人员在编程中旺旺忽略了对象和引用的 区别

package hello;

public class TestRef {
    private Obj aObj = new Obj();
    private int aInt = 0;

    public Obj getaObj() {
        return aObj;
    }

    public int getaInt() {
        return aInt;
    }

    public void changeObj(Obj inObj){
        inObj.setStr("changed value");
    }

    public void changeInt(int inInt){
        System.out.println("----------inInt"+inInt);
        inInt = 1;
        System.out.println("----------inInt"+inInt);
    }

    public static void main(String[] args) {
        TestRef oRef = new TestRef();
        System.out.println("*******************引用类型***********************");
        System.out.println("调用changeObj前"+oRef.getaObj());
        oRef.changeObj(oRef.getaObj());
        System.out.println("调用changeObj后"+oRef.getaObj());
        System.out.println("*******************基本数据类型***********************");
        System.out.println("调用changeInt前"+oRef.getaInt());
        oRef.changeInt(oRef.getaInt());
        System.out.println("调用changeInt后"+oRef.getaInt());
    }

}

class Obj{

    private String str = "default value";

    public void setStr(String str) {
        this.str = str;
    }

    public String toString() {
        return str;
    }
}
------------------------------------------------------------------
运行结果:
*******************引用类型***********************
调用changeObj前default value
调用changeObj后changed value
*******************基本数据类型***********************
调用changeInt前0
----------inInt0
----------inInt1
调用changeInt后0

结论:
java在处理基本数据类型(例如int,char,double等)时,都是采用按值传递(传递的是输入参数的复制)的方式执行,除此之外的其他类型都是按引用传递(传递的是对象的一个引用)的方式执行。对象除了在函数调用时是引用传递,在使用“=”赋值时也采用引用传递。
示例代码如下:

package hello;

public class TestRef {
    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = a;
        b.changeInt();
        System.out.println("a:"+a.getaInt());
        System.out.println("b:"+b.getaInt());
    }
}

class Obj{
    private int aInt = 0;

    public int getaInt() {
        return aInt;
    }

    public void setaInt(int aInt) {
        this.aInt = aInt;
    }

    public void changeInt(){
        this.aInt = 1;
    }
}

-------------------------------------------------------------------
运行结果如下:
a:1
b:1

在实际编程中,经常会遇到从某个已有的对象A创建出另外一个与A具有相同状态的对象B,并且B的修改不会影响A的情况。例如原型模式中就需要clone一个对象实例。
在java中,仅仅通过简单的赋值操作显然无法达到这个目的。而java提供了一个简单有效的clone方法来满足这个需求。
使用clone方法的步骤:

1)继承Cloneable接口
2)在类中重写Object类中的clone方法
3)在clone方法中调用super clone方法
4)把浅赋值的引用指向原型对象新的克隆体。

对上面的例子引入clone方法如下:(浅复制)

package hello;

public class TestRef {
    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = (Obj) a.clone();
        b.changeInt();
        System.out.println("a:"+a.getaInt());
        System.out.println("b:"+b.getaInt());
    }
}

class Obj implements Cloneable{
    private int aInt = 0;

    public int getaInt() {
        return aInt;
    }

    public void setaInt(int aInt) {
        this.aInt = aInt;
    }

    public void changeInt(){
        this.aInt = 1;
    }

    public Object clone(){
        Object o = null;
        try {
            o = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}

当类中只有一些基本的数据类型时,采用上述方法就可以了,但是当类中饱含一些对象时,就需要用到深复制了。实现方法时在对对象调用clone方法完成复制后,接着对对象中的非基本数据类型的属性也调用clone()方法完成深复制。
深度复制如下所示:

package hello;

import java.util.Date;

public class TestRef {
    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = (Obj) a.clone();
        b.changeDate();
        System.out.println("a:"+a.getBirth());
        System.out.println("b:"+b.getBirth());
    }
}

class Obj implements Cloneable{
    private Date birth = new Date();

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public void changeDate(){
        this.birth.setMonth(4);
    }

    public Object clone(){
        Obj o = null;
        try {
            o = (Obj) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        //实现深度复制
        o.birth = (Date) this.getBirth().clone();

        return o;
    }

}

浅复制和深复制的区别:

浅复制仅仅复制所考虑的对象,而不复制他所引用的对象。
深复制把复制的对象所引用的对象都复制了一遍。

11:什么是反射机制:

反射机制能够实现在运行时对类进行装载。
具体而言:反射机制提供的功能主要有:
    得到一个对象所属的类;
    获取一个类的所有成员变量和方法
    在运行时动态创建对象(最重要)
    在运行时调用对象的方法

使用反射机制在运行时动态地创建类的对象

package hello;

public class Test {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("hello.Sub");
            Base b = (Base) c.newInstance();
            b.f();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

class Base{
    public void f(){
        System.out.println("Base");
    }
}

class Sub extends Base{
    public void f(){
        System.out.println("Sub");
    }
}

在反射机制中,class是一个非常重要的类,有三种方法可以获得class类

1)class.forName("类的路径");
2)类名.class
3)实例.getClass().

Java创建对象的方式有哪4种:

1)通过new语句实例化一个对象
2)通过反射机制创建对象
3)通过clone()方法创建一个对象
4)通过反序列化的方式创建对象

12.package有什么作用
package的宗旨 是:把.java文件,.class文件,以及其他的resources文件有条理的进行一个组织,以供使用。

1)提供多层命名空间,解决命名冲突
2)对类按功能进行分类,使项目的组织更加清晰

13.如何实现类似于C语言中函数指针的功能

函数指针:其最重要的功能是实现回调函数。
例如:程序员小明编写了一段程序a,其中预留有回调函数借口,并封装好了该程序,程序员小李要让a调用自己的程序b的一个方法,于是,他通过a中的接口回调属于自己的程序b中的那个方法。

你可能感兴趣的:(知识)