Java基础系列之基本概念

Java基础预计写十个系列…
持续更新中…

1.基本概念

1.1 Java语言有哪些优点?

  1. Java为纯面向对象的语言;
  2. 平台无关性、可移植性。“一次编译,到处执行”!java为解释型语言;
  3. Java提供了很多内置类库,提高了开发效率;
  4. 提供了对Web应用开发的支持,如:Applet、Servlet和JSP开发Web应用;Socket、RMI开发分布式应用程序的类库;
  5. 具有很好的安全性和健壮性。如:Java的强类型机制、垃圾回收器、异常处理和安全检查机制;
  6. 去除了C++中难以理解、容易混淆的特性,例如头文件、指针、结构、单元、运算符重载、虚拟基础类、多重继承等,使得程序更简洁、严谨。

1.2 Java和C++有什么异同

  1. Java为解释型语言。C++为编译型语言;
  2. Java为纯面向对象语言,所有代码必须在类中实现,除基本数据类型外,所有的类型都是类。C++兼具面向对象和面向过程编程的特点,可以定义全局变量和全局函数;
  3. Java没有 指针 操作,程序更加安全;
  4. Java语言不支持多 继承 ,但java引入了接口,可以同时实现多个接口。由于接口具有多态性,因此在Java语言中可以通过实现多个接口来实现C++中的多重继承类似的目的;
  5. Java语言提供了垃圾回收器来实现垃圾的自动回收,当 垃圾回收器 释放无用对象的内存时,首先会调用该对象的finalize()方法;C++需要手动的管理内存分配,通常会把释放资源的代码放到 析构函数 中。

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

程序的入口方法,main()JVM识别的特殊方法名。 public是权限修饰符,表示任何类和对象都可以访问这个方法,static 表明 main() 是一个静态方法,表示方法中的代码是存储在静态存储区的,只要类被加载,就可以使用该方法而不需要通过实例化对象来访问,必须有public static修饰,返回值为void;JVM找不到,就会报错。

程序运行时,第一个执行的方法就是main()方法。通常来讲,执行一个类的方法,先必须实例化一个类的对象,然后通过对象来调用这个方法。但由于main是程序的入口方法,此时还无实例化对象,因此 在编写main()方法时就不需要实例化对象就可以调用这个方法 ,so,main()方法要被定义成public与static。

main方法定义的其他格式 ?

static public  void main(String[] args)
public static final void main(String[] args)
public static synchronized void main(String[] args)

由于main()方法作为程序的入口方法,因此 不能用abstract关键字 来修饰。

同一个.java文件中是否可以有多个main() 方法 ?

public class Test {
	public static synchronized void main(String[] args) {
		System.out.println("Test main!");
	}
}

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

运行结果:Test main!

1.4 如何实现在main()方法执行前输出 “Hello World!” ?

程序运行时,最先加载的就是main()方法,是否意味着main()方法就是程序运行时第一个被执行的模块呢?
不对。 静态块在类被加载时就会被调用。和代码顺序无关!

public class Test {
	static {
		System.out.println("Hello World1!");
	}

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

运行结果:Hello World1!
     Hello World2!

1.5 Java程序初始化的顺序是怎样的?

Java程序的初始化一般遵循的原则:

  • 静态对象(变量)优先于非静态的对象(变量)初始化,其中,静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次。
  • 父类优先于子类进行初始化。
  • 按照成员变量的定义顺序进行初始化。

初始化顺序:

  1. 父类静态变量、静态代码块
  2. 子类静态变量、静态代码块
  3. 父类非静态变量、非静态代码块、构造器 & 子类非静态变量、非静态代码块、构造器
package org.base;

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();
	}
}

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

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

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

1.6 Java中的作用域有哪些?

{ } 决定了其定义的变量名的可见性与生命周期。

变量类型: 成员变量、静态变量、局部变量。

类成员变量类的实例化对象 的作用范围相同。当类被实例化时,成员变量就会在内存中分配空间并初始化,直到这个被实例化对象的生命周期结束时,成员变量的声明周期才结束。被 static修饰的变量 成为静态变量或全局变量,与成员变量不同的是,静态变量不依赖于任何实例,而是被所有实例所 共享,也就是说,只要有 一个类被加载,JVM就会给类的静态变量分配存储空间。 因此,就可以通过 类名.变量名 来访问静态变量。
   
              作用域对比

作用域与可见性当前类同一package子类其他package
public
protected×
default××
private×××
  • public。当前项目。 表明该成员变量和方法对所有类或对象都是可见的,所有类或对象都可以直接访问。
  • protected。当前包。 表明成员变量或方法对该类自身,与它在同一包中的其他类,在其他包中该类的子类都可见。
  • default当前包无子类。 表明该成员变量或方法只有自己和与其位于同一包内的类可见。若父类与子类位于同一个包内,则子类对父类的default成员变量或方法都有访问权限;若父类与子类位于不同package内,则无访问权限
  • private。当前类。表明该成员变量或方法是私有的,只有当前类对其有访问权限。

default方法使用: 1.switch语句;2.接口中使用;

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

可以。但最多只能有一个类被public修饰并这个类名必须与文件名相同,若这个文件没有public类,则文件名是任意一个类名即可。javac 指令编译 .java 文件,会给每一个类生成一个对应的 .class 文件。

1.8 什么是构造函数?

一种特殊函数。用来对象实例化时 初始化对象 的成员变量。

构造函数特点:

  1. 构造函数必须与类名相同,无返回值,也不能有void
  2. 每个类可以有多个构造函数,无手写构造函数,调用默认构造器;有手写构造函数,调用手写构造函数;
  3. 构造函数参数可以有任意个;
  4. 构造函数 伴随着new操作一起调用,由系统调用。只运行一次,而普通的方法是在程序执行到它时被调用,且可以被调用多次。
  5. 构造器不能被继承,因此不能被覆盖,可以重载(参数个数和参数类型 )。
  6. 当有父类时,在实例化对象时会先执行父类的构造函数,然后执行子类的构造函数。 当父类没有提供无参构造器时,子类的构造函数中必须显示的调用父类的构造器,否则会编译出错。 如果父类提供了无参数构造器,子类就可以不显示的调用,默认调用无参构造器。
package org.base;

public class Test extends B {
	public static void main(String[] args) {
		Test test = new Test();
		Test test2 = new Test(1);
	}

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

	public Test(int a) {
		super(a); // super();  也OK
		System.out.println("Test Constructor2.");
	}
}

class B {
	public B() {
		System.out.println("B Constructor1.");
	}

	public B(int a) {
		System.out.println("B Constructor2.");
	}
}

运行结果:B Constructor1.
     Test Constructor1.
     B Constructor2.
     Test Constructor2.

1.9 为什么Java中有些接口没有任何方法?

  • 接口是抽象方法定义的集合,是一种特殊的抽象类;
  • 一个类通过实现接口的方式,来继承接口的抽象方法;
  • 接口中只包含方法的定义,没有方法的实现;
  • 除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
package org.base;

public class Test implements H{
	public static void main(String[] args) {
		
	}
	public void m(){ // 实现接口中所有方法,否则定义此类为abstract类
	
	}
}

interface H{ // 隐式抽象接口
	public void m();// 默认是abstract类,权限修饰符只能为public
}

接口有以下特性:

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的

接口与类的区别:

  1. 接口不能用于实例化对象。
  2. 接口没有构造方法。
  3. 接口中所有的方法必须是抽象方法。
  4. 接口不能包含成员变量,除了 static 和 final 变量。
  5. 接口不是被类继承了,而是要被类实现。
  6. 接口支持多继承。

抽象类和接口的区别

  1. 抽象类中的方法可以有 方法体,就是能实现方法的具体功能,但是接口中定义的方法必须是抽象方法,如:(abstract) void m();
  2. 抽象类中的 成员变量 可以是各种类型的,而接口中的成员变量只能是 public static final 类型的并被初始化。
  3. 接口中 不能含有静态代码块 以及 静态方法 ,而抽象类是可以有静态代码块和静态方法。
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

注: Java8开始,接口可以有默认方法与静态方法;

package org.base;

public class Default implements T {
	@Override
	public void m2() {// 必须实现所有抽象方法,否则声明此类为abstract类
		System.out.println("This is m2 method.");
	}

	public static void main(String[] args) {
		T.m();
		Default test1 = new Default();
		test1.m1();
		test1.m2();
	}
}

interface T {
	static void m() {// Java8新增的静态方法
		System.out.println("This is m method.");
	}

	default void m1() {// 默认方法
		System.out.println("This is m1 method.");
	}

	void m2();// 没有实现的抽象方法
}

标识接口:接口内部没有声明任何方法,仅充当一个标识作用。Java类库中已存在的标识接口中有 CloneableSerializable 等。使用时会经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。

例子:开发一款游戏,有一个专门负责出去寻找有用的材料,假设这个人物只收集矿石和武器,而不会收集垃圾,通过接口标识实现这个功能。

package org.base;

import java.util.ArrayList;

interface Stuff{}
// 矿石
interface Ore extends Stuff{}
// 武器
interface Weapon extends Stuff{}
// 垃圾
interface Rubbish extends Stuff{}
// 金矿
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 Weapon{
	public String toString() {
		return "Grenade";
	}
}
class Stone implements Rubbish{
	public String toString() {
		return "Stone";
	}
}

public class TestInterface {
	public static ArrayList<Stuff> collectStuff(Stuff[] s){
		ArrayList<Stuff> 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<Stuff> 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));
		}
	}
}

修饰外部 interface 的修饰符有:public、abstract

1.10 Java中的clone 方法有什么作用?

Java中没有明确提供指针的概念与用法,实质上每个 new 语句返回的都是一个指针的引用,由于Java取消了指针概念,在编程中会忽略对象和引用的区别。

Java在处理基本数据类型时,都是按值传递进行处理的,除此之外的其他类型都是按引用传递的方式。

package org.base;

public class Clone {
	public static void main(String[] args) {
		Obj a = new Obj();
		Obj b = a; // 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
     
clone() 方法: 已有的对象A创建出另外一个与A具有相同状态的对象B,并且对B改变不会影响A的状态。Object类中提供了一个clone()方法。这个方法的作用是返回一个Object对象的复制(新的对象而非引用)。

clone方法的使用步骤:

  1. 实现clone的类首先需要 继承 Cloneable 标识接口
  2. 重写Object 类中的clone()方法
  3. 在clone方法中 调用super.clone()
  4. 把浅复制的引用指向原型对象新的克隆体。
package org.base;

public class Clone {
	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 = (Obj)super.clone();  // throws或try-catch抛异常
		} catch (CloneNotSupportedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return o;
	}
}

运行结果:a:0
     b:1

浅复制和深复制:如何选择?

  1. 检查类中有无基本类型(对象的数据成员)。若无,返回super.clone()。
  2. 若有,确保类中包含的所有非基本类型的成员变量都实现了深复制。

执行过程:

Object o = super.clone(); // 执行浅复制
对每一个对象attr执行以下语句:// 执行深复制
o.attr = this.getAttr().clone();
最后返回 o

package org.base;

import java.util.Date;

public class Clone {
	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) {
			// TODO: handle exception
			e.printStackTrace();
		}
		// 实现深复制
		o.birth = (Date) this.getBirth().clone();
		return o;
	}
}

运行结果:a:Sun Oct 13 18:16:50 CST 2019
     b:Mon May 13 18:16:50 CST 2019

浅复制和深复制有什么区别?

浅复制(Shallow Clone):仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(Deep Clone):深复制把复制的对象所引用的对象都复制了一遍。

假如定义如下一个类:

public Test {
	public int i;
	public StringBuffer s;
}

在这里插入图片描述
深复制与浅复制的区别。

1.11 什么是反射机制

反射机制允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作。实际开发用的不多。

反射机制提供的功能主要有:

  • 得到一个对象所属的类;
  • 获取一个类的所有成员变量和方法;
  • 在运行时调用对象的方法。
  • 在运行时动态的创建类的对象;
package org.base;

public class Reflect {
	public static void main(String[] args) {
		try {	// 使用反射机制加载类
			Class c = Class.forName("org.base.Sub");
			Base b = (Base)c.newInstance();
			b.f();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

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

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

运行结果:Sub

获取Class类的三种方法:

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

Java创建对象的方式有几种?

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

1.12 package有什么用?

package:包含.java源文件、.class编译文件、resource文件(.xml、.avi、.mp3、.txt文件)条理性进行组织。类似于Linux文件系统。
简单来讲 package由 class 和 interface组成

作用:

  1. 提供多层命名冲突。不同package可以存在相同名。
  2. 对类按功能进行分类。若不使用package,代码可读性差、可维护性差。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值