Java基础知识——1、Java基本概念

1、Java基本概念

1.1 Java语言有哪些优点

1)Java为纯面向对象语言:
	     它能够直接反应现实生活中的对象,因此开发人员通过Java使编写程序更为简易
	     
2)平台无关性:
	Java语言可以"一次编译,到处运行",无论在Windows平台或者是Linux、MacOS等其他平台对Java程序进行编译,编译后的程序在任意平台都可以运行
	
3)Java提供了很多的内置库,通过这些类库可以简化开发人员的程序设计工作,同时缩短项目开发时间。

4)提供了对Web应用开发的支持:
	例如Applet、Servlet和JSP可以用来开发Web应用程序;Socket、RMI可以用来开发分布式应用程序得类库。
	
5)具有较好的安全性和健壮性:
	Java语言经常被用在网络环境中,为了增强程序的安全性,Java语言提供了一个防止恶意代码攻击的安全机制(数组边界检测与Byteccode校验等)。
	Java的强制类型机制,垃圾回收器、异常处理和安全检测机制使得用Java语言编写的程序有良好的健壮性

1.2 Java与C/C++有什么异同

Java语言是C++语言改进并重新设计而来。

Java与C++都是面向对象语言,都使用了面向对象思想(如封装、继承、多态等),
并且由于面向对象有许多非常好的特性(继承、组合等),因此二者都有很好的可重用性。

以下为不同点

 1)Java为解释性语言,程序由源码经过Java编译器编译成字节码,然后由JVM解释执行。
    C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码。
    因此Java执行慢但能够跨平台执行。C/C++执行快但却不能跨平台。
    
2)Java为纯面向对象语言,所有代码(包括函数、变量等)必须在类中实现。除基本数据类型(如int、float、byte等)外,所有类型都是类。
此外Java语言中不存在全局变量和全局函数。
   C++语言兼具面向过程和面向过程编程的特点,所以C++可以定义全局变量和全局函数。
   
3)Java语言中没有指针的概念,在C++语言中操作指针可能引起系统问题,而Java没有指针概念,从而使程序变得更加安全。

4)Java语言不支持多重继承,但却引入了接口的概念,可以同时实现多个接口。
又因为接口具有多态特性,因此Java语言中可以通过实现多个接口来实现C++语言中的多继承

5)Java语言提供了垃圾回收器来实现垃圾的自动回收,不需要程序显式的管理内存分配。
Java语言引入了finalize()方法,当垃圾回收器将要释放无用对象的内存时,首先会调用finalize()方法。
因此开发人员不需要关心对象所占内存空间何时会被释放。
   在C++语言中,开发人员需要去管理内存的分配(包括申请与释放),在C++语言中,通常会把释放资源的代码放到析构函数中
   
6)Java语言不支持运算符重载
   C++语言支持运算符重载

7)Java语言没有预处理,但是提供import机制
   C++支持预处理

8)Java语言不支持默认函数参数
   C++支持默认函数参数

9)Java语言不提供goto语句,但是goto是保留关键字
   C++支持goto语句

10)Java语言不支持强制类型转换,需要开发人员显式的进行强制类型转换
  C++支持强制类型转换,这会导致程序不安全

1.3 为什么需要public static void main(String [] args)方法

public static void main(String [] args)为Java程序的主入口方法,JVM在运行程序时,会首先查找main()方法。其中,public是权限修饰符,表明任何类或者对象都可以访问这个方法。static表明main()方法是一个静态方法,方法中的代码是存储在静态存储区的只要类加载后,就可以使用该方法且不需要通过实例化对象来访问,可以通过类名.main()直接访问。
  JVM在启动时会按照上述方法的签名来查找方法的入口地址,找到就执行,找不到就报错。
  void表明方法没有返回值,main是JVM识别的特殊方法名,是程序入口方法。字符串数组参数args为开发人员在命令状态下与程序交互提供了一种手段
  因为main是程序的入口方法,所以当程序运行时第一个执行的方法就是main方法。
  通常来讲要执行一个类的方法,先必须实例化一个类的对象,然后通过对象来调用这个方法,但是由于main是程序的入口方法,此时还没有实例化对象,因此在编写main()方法时就要求不需要实例化对象就可以调用此方法,鉴于此,main()方法需要被定义成public与static。

引申:
1、main()的其他可用定义格式
static public void main(String [] args)       ——>public与static没有先后关系,所以此定义是合理的
public static final void main(String [] args)     ——>main()方法也可以定义为final
public static synchronized void main(String [] args) ——>main()方法也可以用synchronized 来修饰
不管什么样的定义方式,都必须保证main()方法的返回值为void,且有static与public关键字修饰。同时由于main()方法为程序主入口,所以不能用abstract关键字来修饰。

2、同一个.Java文件中是否可以有多个main()方法?
每个类中都可以定义main()方法,但是只有与文件名相同的用public修饰的类中的main()方法才能作为整个程序的入口方法
如:

class Tpublic static void main(String [] args){
		System.out.println("T main");
	}
}

class Test{
	//程序入口主函数
	public static void main(String [] args){
		System.out.println("Test main");
	}
}

运行结果为:
Test main

1.4 如何实现在main()方法执行前输出"Hello World"

在Java语言中,由于静态块在类被加载时就会被调用,因此可以在main()方法执行前,利用静态实现输出"Hello World"
例:

public class Test {
    
    
    static{
    
    
        System.out.println("在main()方法之前执行Hello Word");
    }

    public static void main(String[] args) {
    
    
        System.out.println("Hello Word");
    }
}

结果为:
在main()方法之前执行Hello Word
Hello Word

由于静态块不管顺序如何,都会在main()方法之前执行,因此以下代码会与上面的代码有相同的输出结果。

public class Test {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("Hello Word");
    }
    
    static{
    
    
        System.out.println("在main()方法之前执行" + "Hello Word");
    }
}

结果为:
在main()方法之前执行Hello Word
Hello Word

1.5 Java初始化的顺序是如何的

在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。

 Java程序的初始化一般遵循三个原则:
  1、静态对象优先于非静态对象初始化
     静态对象(常量)只初始化一次,非静态对象(变量)可初始化多次
  2、父类优先于子类初始化
  3、按照成员变量的的定义顺序进行初始化
     变量定义散布于方法定义之中,他们依然在任何方法(包括构造函数)被调用之前先初始化

Java程序初始化工作可以在许多不同的代码块中来完成,他们的执行顺序如下:
 父类静态变量>父类静态代码块>子类静态变量>子类静态代码块>父类非静态变量>父类非静态代码块>父类构造函数>子类非静态变量>子类非静态代码块>子类构造函数
例:

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

    public static void main(String[] args) {
    
    
        System.out.println("Base block");
    }

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

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

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

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

程序运行结果:
Base static block
Derived static block
Base block
Base constructor
Derived block
Base constructor

1.6 Java作用域有那些

在计算机程序中,声明在不同地方的变量具有不同的作用域,例如局部变量、全局变量等。在Java语言中,作用域是由花括号的位置决定的,它决定了其定义的变量名的可见性和生命周期。
  在Java语言中,变量的类型主要有三种:成员变量、静态变量、和局部变量。类的成员变量的作用范围与类的实例化对象作用范围相同,当类被实例化时,成员变量就会在内存中分配空间并初始化,直到这个实例化对象的生命周期结束时,成员变量的生命周期才结束。被static修饰的成员变量被称为静态变量或者是全局变量,与成员变量不同的是,静态变量不依赖于特定的实例,而是被所有势力所共享,也就是说。只要有一个类被加载,JVM就会给类的静态变量分配存储空间。因此就可以通过类名或者变量名来访问静态变量。
  
  此外,成员变量有4种作用域,如下表:

作用域与可见性 当前类 同一package 子类 其他package
public
private × × ×
protected ×
default × ×

1)public:表明该成员变量或方法对所有类或者对象都是可见的,所有类或者对象都可以直接访问。
2)private:表明该成员变量或方法是私有的,只有当前类对其拥有访问权限。
3)protected:表明该成员变量或方法对该类自身,与它在同一包中的其它类,在其他包中的该类子类都可见。
4)default:表明该成员变量或方法只有自己和与其位于同一包内的类可见。若父类与子类位于同一包中,则子类对父类的default成员变量或方法都有访问权限;若父类与子类不位于同一包中,则没有访问权限。

注:
这些修饰符只能修饰成员变量,不能用来修饰局部变量。
private与protected不能用来修饰外部类。

1.7 一个Java文件中是否可以定义多个类

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

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

public class Derived extends Base {
    
    
    public static void main(String[] args) {
    
    
        Base b = new Derived();
        b.print();
    }
}

使用javac Derived.java指令编译上述代码,会生成两个字节码文件:Base.class和Derived.class,然后使用java Derived指令执行代码,此时控制台将会输出:Base

1.8 什么是构造函数

构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量。在Java语言中,构造函数具有以下特点:

  1)构造函数必须与类的名字相同,并且不能有返回值(返回值也不能为void)。
  
  2)每个类可以有多个构造函数。
  
  3)构造函数可以有0个、1个或1个以上的参数。
  
  4)构造函数总伴随着new操作一起调用,且不能有程序编写者直接调用,必须要有系统调用。
  构造函数在对象实例化时会被自动调用,且只运行一次;而普通方法是在程序执行到它时被调用,且可以被该对象多次调用。
  
  5)构造函数主要作用是完成对象的初始化工作。
  
  6)构造函数不能被继承,因此也不能被覆盖。但构造函数可以重载。
  
  7)子类可以通过super关键字来显示的调用父类的构造函数,当父类没有提供无参数的构造函数时,子类的构造函数中必须显式地调用父类的构造函数。
  当有父类时,在实例化对象时会先执行父类的构造函数然后执行子类的构造函数。
  
  8)当父类与子类都没有定义构造函数时,编译器会为父类生成一个无参的构造函数,也会为子类生成一个无参的构造函数。
  此外默认构造函数的修饰符和当前类的修饰符有关。

1.9 Java中clone方法有什么用

   在实际编程中,经常会遇到从某个已有的对象A创建出一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态,例如在Prototype(原型)模式中就需要用clone一个对象实例。在Java语言中,仅仅通过简单的赋值操作是无法满足这个要求的,所以Java提供了一个简单有效的clone()方法来满足这个需求。
  Java中所有类都默认继承Object类,而Object类提供一个clone()方法。这个方法的作用是返回一个Object对象的复制。这个复制返回的是一个新的对象,而不是一个对象的引用。
  
  下面是clone()方法的步骤:
  1)实现clone类首先需要继承Cloneable接口。(Cloneable接口实质上是一个表示接口,无任何方法)
  2)在类中重写Object类中的clone()方法。
  3)在clone方法中调用super.clone()。
  4)把浅复制的引用指向原型对象新的克隆体。

class Obj implements Cloneable {
    
    
    private int aInt = 0;

    public Obj(int aInt) {
    
    
        this.aInt = aInt;
    }

    public int getaInt() {
    
    
        return aInt;
    }

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

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

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

输出结果:
a:0
b:1

Java语言在重载clone()方法时存在浅复制和深复制之分,当类中只有一些基本的数据类型时,采用浅复制。但是当类包含一些对象时,就需要用到深复制。实现方法是在对对象调用clone()方法完成复制后,接着对对象中的非基本类型的属性也调用clone()方法完成深复制

引申:浅复制和深复制的区别
  浅复制:被复制的所有对象都含有原来对象相同的值,而所有对其他对象的引用仍然指向原来的对象。(仅复制所考虑对象,而不复制它所引用的对象)

  深复制:被复制的所有对象都含有原来对象相同的值,除去那些引用其他对象的变量。那些引用其他变量的对象将指向被复制的新对象,而不再是那些原有的被引用的对象。(把复制的对象所引用的对象都复制了一遍)

1.10 什么是反射机制

  反射机制是Java语言中非常重要的特性,它允许程序在运行时进行自我检查,同时也允许对于内部成员进行操作。虽然这个特性在实际操作中使用不多,但是其他语言根本就没有提供这样的特性。
  由于反射机制能够实现运行时对类进行装载,因此能够增加程序的灵活性,但是不恰当地使用也会严重影响系统的性能。

反射机制主要提供的功能有:
 1)得到一个对象所属的类
 2)获取一个类的所有成员变量与方法;
 3)在运行时创建对象
 4)在运行时调用对象方法

反射机制非常重要的一个作用是可以在运行时动态的创建类的对象,例:

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

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

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

程序运行结果为:
Sub

在反射机制中Class是一个非常重要的类,获取Class类的三种方法:

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







注:

此文来源于《Java程序员面试笔试宝典》一书

仅作为本人学习过程的记录

填写原创是因为找不到相关链接

如有不妥请联系本人,会立即删除

此书对于我这种小白来说非常有用,讲解详细,知识点全面,目前正在根据此书学习,陆续会记录更多知识点。

猜你喜欢

转载自blog.csdn.net/HF0705/article/details/114058807