安卓开发快速入门笔记(1)——Java基础

文章目录

  • JAVA环境构成
    • Java运行环境构成
    • Java程序运行过程
  • Java程序编写
    • 变量定义
    • 函数
      • 重载
    • 循环
      • for循环
      • while循环
      • do while循环
    • 分支语句/条件语句
      • if语句
      • switch语句
      • 类的定义:
      • 对象:
        • 1.实例化对象:
        • 2.对象的生命周期:
        • 3.对象的比较:
        • 4.构造函数:
        • 5.this
        • 6.对象的强制类型转换
      • 垃圾回收
    • 关键字
      • 访问控制
      • 类、方法、变量修饰符
      • 程序控制
      • 异常处理
      • 包相关
      • 基本类型
      • 变量引用
      • 保留字
    • 内部类
    • 类的继承
      • 继承的定义
      • 子类对象的实例化过程
      • 继承中的函数重载
    • 抽象类
    • 接口
    • 注解、注解类
  • 面向对象三大特性
    • 多态性
    • 封装性
    • 继承性
  • 异常处理
  • 多线程
  • 文件
  • 设计模式
    • 单态设计模式
  • Java的反射机制
  • JNI

(Java基础)该文章适用于 有C语言基础,想从 面向过程过渡到 面向对象的读者

JAVA环境构成

简单介绍:
1.Java程序的运行环境由哪些文件组成
懒,先不写
2.Java程序运行过程
懒,先不写,空着

Java运行环境构成

先不写

Java程序运行过程

1.图
略,先不写
2.java源文件编译成class文件
Java代码写在 .java 文件中, .java 文件经 javac 编译后,会在 .java 文件当前目录下,将 .java 代码中的每一个类,都生成一个 .class 文件(.clas文件又称为Java字节码)。如:

demo1.java 中的代码为

class Test1
{
}

在DOS窗口下使用命令

javac demo1.java

对Java代码进行编译。经javac编译之后,会生成一个名为Test1.class的Java字节码文件

demo2.java 中的代码为:

classTest2
{
}
class Test3
{
}

javac编译之后,会生成一个名为Test2.class和一个名为Test3.class的Java字节码文件

3.Java虚拟机会根据classpath这个环境变量去寻找.class文件,再解释运行.class程序时,只需执行

java Test1

而不是

java Test1.class

Java程序编写

变量定义

1.在函数中用int,char,float,byte等关键字定义的变量或数组分配的是栈内存,当函数调用结束时,栈空间自动释放

2.new定义的对象或数组分配的是堆内存 ,由Java虚拟机的自动垃圾回收期管理

3.引用变量
在栈中的变量,其值可以是堆中分配的数组或对象的内存起始位置,如

int x[] = new int[100]

在栈中定义了一个变量x,在堆中定义了一个数组,x的值是数组在堆内存中的起始位置。因此,上述代码,可改写为

int x[];
x = new int[100];

其结果与过程相同。
即使栈中的变量被回收,堆中的变量或对象仍有可能未被回收,仍可以存在。

4.数组的定义,与C语言不同的是,不能定义数组的长度,否则编译时会出错。数组定义举例:

int x[] = {1,2,3,4};		//静态数组  定义,生成了一个包含四个元素的数组
string x[];					//定义一个字符串型数组
int [] x = {1,2,3,4};		//定义数组时,[]可以在关键字后,也可以在变量名后
int [] x = new int[]{1,2,3,4};	//定义一个含有四个元素的数组;详见引用变量
int x[5];					//错误定义

多维数组定义:与C语言不同的是,Java中并没有像C语言中那样真正意义上的多维数组,而是数组中的数组,数组中的元素也是数组,类似于python中的多维数组概念。定义定义多维数组的方法如下:

int xx[][];			//定义了一个数组中的数组(多维数组)
xx = new int [3][];	//将xx引用到一个有三个元素的多维数组对象中
xx[0] = new int[3];	//xx[0]中则有三个元素
xx[1] = new int[2];	//xx[1]中则有两个元素
					//xx[2]未赋值,则xx[2]==null
					
int xx1 [][] = new int [2][3];	//则生成一个2*3的数组对象
int xx2[][]={{1,2},{3,4,5},{6,7}}	//多维数组静态初始化

5.非基本类型变量定义
在定义基本类型变量的时候使用关键字,如:

int x;
private String y;

其中的关键字int则表示变量x的返回值是数值型;String则表示变量y的返回值是字符串型。如果需要定义一个返回值为某个类的类型时,可以用如下方式:

class A		//事先已有一个类A 
{
}

class B
{
	private A m;	//在类B中创建了一个私有变量m,其返回值为类A的类型
}

函数

1.与C语言函数定义类似

2.关键字修饰
Java的函数定义,必须用关键字对返回值的进行修饰,如果无返回值,则可用void修饰。
3.函数的调用
方法是定义在类中的,因此要调用方法的时候,一定是某个对象要调用这个方法,因此Java中的函数调用方法是如下格式:

对象名.方法名(参数);

重载

函数的重载即在类中有多个同名的函数,但是每个函数的参数个数不同(每个参数的类型当然也可以不同),例如:

class Person
{
	String name = "unknow";
	int age = 0;

	public void people_say()	//定义people_say()函数
	{
		System.out.println("My name is "+name+" and I'm "+age+" years old.FUN1");
	}
	public void people_say(String per_name)	//重载people_say()函数
	{
		name = per_name;
		System.out.println("My name is "+name+" and I'm "+age+" years old.FUN2");
	}
	public void people_say(String per_name,int per_age)	//重载people_say()函数
	{
		name = per_name;
		age = per_age;
		System.out.println("My name is "+name+" and I'm "+age+" years old.FUN3");
	}


	public static void main(String arg[])
	{
		Person p = new Person();
		
		//传入不同参数调用people_say()函数
		p.people_say();						
		p.people_say("Tom");
		p.people_say("Bob",16);
	}
}
-----------------------------------------
输出结果如下:
My name is unknow and I'm 0 years old.FUN1
My name is Tom and I'm 0 years old.FUN2
My name is Bob and I'm 16 years old.FUN3

函数的重载是面向对象三大特征之一——多态的表现形式之一。
可以被子类(在后面的继承中会讲子类是什么)重载的方法叫做虚方法 ,个人对虚方法的理解并不到位,网上的资料好像都是跟C#有关的,Java的虚方法,我在想,是不是不需要用virtual来修饰也可以,只要是能被重载,就叫虚方法。

注意
Java语言在定义函数时不能给参数赋默认值,需要赋默认值,只能通过函数重载来实现。如:

class Person
{
	public void people_say()
	{
		String name = "unknow";
		int age = 0;
		people_say(name,age);	//调用重载函数并传入参数
	}
	public void people_say(String name,int age)	//重载people_say()函数
	{
		System.out.println("My name is "+name+" and I'm "+age+" years old.");
	}

	public static void main(String arg[])
	{
		Person p = new Person();
		p.people_say();	//传入空参数
	}
}
-----------------------------------------
输出结果如下:
My name is unknow and I'm 0 years old.

循环

for循环

1. 与C语言类似

for(表达式1;表达式2;表达式3)
{
	
}

a)第一次进入for循环的时候,先执行表达式1,并判断表达式2是否为真,为真,则执行循环体,为假则结束for循环。
b)当第一次循环结束时,执行表达式3,再判断表达式2是否为真,为真则执行循环体,为假则结束循环。
c)重复步骤b直到表达式2为假。

2. 增强for循环
参考 https://jingyan.baidu.com/article/455a9950570b91a166277809.html

while循环

do while循环

1.语法格式:

do
{
	//代码块
	
}while(布尔表达式)

2.注意:
do while语句会无条件执行一遍do中的代码,执行完后再判断while()中的表达式是否成立,成立则再循环一次执行do中代码。

分支语句/条件语句

if语句

1.语法格式

if (表达式)			//表达式为真,则会进入代码块,否则匹配下面的else if或者else
{
	//代码块
}
else if (表达式)		//可以有多个else if(表达式)
{
	//代码块
}
else				//前面的所有判断都匹配不上,才会匹配到else
{
	//代码块
}

2.注意:
简单的判断并赋值的语句可以通过问号表达式来简化,而不是使用if else语句。问号表达式语法格式为**c=表达式?a:b;**参考下面例程:

int a=1,b=2,c=3,d=4,e=0;
e=(a>b)?c:d;	//问号表达式
System.out.println("e=",e);

--------------------------------------
输出结果为:
e=4

当表达式为真,则赋冒号前面的值给e,当表达式为假,则赋冒号后面的值给e。

switch语句

1.语法格式

switch()
{
	case value1:
		
}

2.注意:
匹配上某一个case之后,如果不使用break退出switch,则会顺序执行下一个case,直到switch块结束;例如

int x=2;

switch(x)
{
case 1:
	System.out.println("x=1");
case 2:
	System.out.println("x=2");
case 3:
	System.out.println("x=3");
default:
	System.out.println("x>=4");
}

则输出结果为

x=2
x=3
x>=4

类的定义:

class Person
{
	int age;		//	类中的成员变量,也称为类的属性
	void shout()	//类中的方法,称为类方法,类方法可以直接访问同一个类中的所有属性
	{
		int age=60;		//类方法中的局部变量会覆盖掉类中的成员变量
		System.out.println("i'm"+age+'years old');
	}
}

如果类方法中的局部变量与类中的成员变量同名,则类方法中的局部变量会覆盖类中的成员变量。
类中的成员变量可以不初始化,编译器会根据数据类型自动进行初始化。除了基本类型之外的变量,都是引用类型。
类在JVM虚拟机中被用到时,才会被装载,而不是程序一开始,就装载所有可能会用到的类。

对象:

1.实例化对象:

实例化出来一个对象,实际上是生成一个引用变量,实例化对象的方法是:

Class AAA = new Class();	//实例化一个对象
new Class();			//无变量引用的对象实例称为匿名对象

类名+变量名,在栈区生成一个叫AAA的变量,这个变量AAA指向在堆区按照Class类为模板生成的一段数据块的首地址。

2.对象的生命周期:

当无变量引用对象时,则对象会变成垃圾,等待垃圾回收器回收。
匿名对象在被引用完之后立即变为垃圾,等待被垃圾回收器回收。

3.对象的比较:

假如有个类,名为Person,则实例化两个对象p1和p2。

Person p1 = new Person();
Person p2 = new Person();

if (p1==p2)
	System.out.println("p1==p2");
else
	System.out.println("p1!=p2");
if (p1.equals(p2))
{
	System.out.println("p1 equals p2");
}
else
{
	System.out.println("p1 not equals p2");
}

因为在实例化时,p1和p2没有传入任何参数,所以p1和p2都是使用默认的参数实例化的,因此类中各属性的值也相等。但是输出结果却是:

p1!=p2
p1 equals p2

出现该结果是因为,“==”判断的是p1和p2所指向的堆内存地址,也就是判断栈中的值,因为是两个独立的对象,所以内存地址不同,因此第一次判断为假。
每个对象都有equals()方法。该方法用于判断两个对象中各属性的值是否相等。即对堆中各变量的数据进行比较。由于p1和p2都是使用默认参数实例化出来的对象,因此各参数相等,也就是equals。

4.构造函数:

什么是构造函数:

class Person	
{	
	//显示初始化
	private String per_name="unknow";	
	private int per_age=0;
	
	//main方法
	public static void main(String arg[])
	{
		Person p1 = new Person();
		Person p2 = new Person("Tom",18);
		Person p3 = new Person("Victor");
		p1.Person();
	}

	//构造方法    注意,构造方法是没有返回类型的
	public Person()
	{
		System.out.println("My name is "+per_name);
	}
	public Person(String person_name)
	{
		per_name=person_name;
		System.out.println("My name is "+per_name);
	}
	public Person(String person_name,int person_age)
	{
		per_name=person_name;
		per_age=person_age;
		System.out.println("My name is "+per_name+" and I'm "+per_age+" years old");
	}
}

	public String Person()
	{
		System.out.println("I'm not Constructor,you can call me anytime and anywhere!");
	}
--------------------------------------------------------
输出结果为:
My name is unknow
My name is Tom and I'm 18 years old
My name is Victor
I'm not Constructor,you can call me anytime and anywhere!

分析在实例化p3时的内存变化:
首先,构造方法在接受传入的参数后,先执行显示初始化,堆中生成一个名为per_name的变量,值为unknow。然后才执行构造方法中的代码,将person_name的值传给per_name

注意:
a.若是定义类时没有定义构造函数,则Java编译器会自动帮我们创建构造函数,这个构造函数不接受任何参数,且代码块为空,不做任何操作。
b.当我们自己定义了构造函数之后,编译器将不再代替我们自动生成不带参数的构造函数。
c.当运行Java程序时,会先执行显示初始化的赋值,才再调用构造方法。
d.构造函数在对象建立之后即被编译器调用,只能被调用一次即不再被调用,不能手动在代码中调用。
e.构造函数没有返回值类型,有返回值类型的只是一个普通方法,不是构造方法。

5.this

作用:
a.用于在类方法中指明是当前对象在调用。举个例子:
首先需要先明确一点,就是,

class A
{
	public void fun1()
	{
	}
	public void fun2()
	{
		A a2 = new A();
		a2.fun1();
	}

	public static void main(String arg[])		//main函数
	{
		A a1 = new A();	//在main函数中实例化一个对象a1
		a1.fun2();		//对象a1调用方法fun2()
	}
}

从上面代码可以看出,a1调用了fun2()fun2() 中实例化了一个对象a2a2再调用fun1(),实际上相当于是对象a1调用了对象a2fun()1;这在Java中是允许的。

如果想要a1从fun2()中调用它自己本身的fun1(),则应该怎么做呢?
可以在fun2中加上如下一行代码

fun1();

也可以在fun1()前面加上this,表示是当前对象a1;

this.fun1();

此时的this,即表示在外面实例化的对象a1。

每个成员方法内部,都会有一个this引用变量,该变量指向对该方法进行调用的对象在堆内存中的首地址。关系如下图所示:
安卓开发快速入门笔记(1)——Java基础_第1张图片
b.从上面的分析可以看出this关键字的意义和作用,但也可以看出,用不用this关键字,其效果也是一样的,那么,this关键字是否有必要使用呢?
其实在有的时候,this关键字还是非用不可的。
看如下错误代码:

class Person
{
	private String name;
	public shout(String name)
	{
		name=name;		//类成员变量与类方法局部变量重名
		System.out.println("My name is "+name);
	}
}

此时,可以改变局部变量名称,已解决重名问题,但是对于代码的可读性,则大打则扣。为了不降低代码可读性,一眼就能看出两个变量是有关系的,且解决重名问题,则需要用到this变量。代码如下:

class Person
{
	private String name;
	public shout(String name)
	{
		this.name=name;		//在类成员变量前加上this关键字
		System.out.println("My name is "+name);
	}
}

在类成员变量前加上this关键字,这样就表示清楚了前面的是对象的一个属性,后面的是方法中的局部变量。重名问题即可解决。
c.在如下情况,也需要使用this关键字
当有一个容器类A,容器类对象a和一个部件类B。在类A的某个方法中,需要实例化类B的一个对象b,把b加到类A的对象a当中,而类B的构造方法,需要接收一个参数,用来表示b在a里。则需要使用this。
先看如下错误代码:

class A
{
	B b;
	public void add_B()
	{
		b = new B(new A());	//语法上是没有错误的,但是逻辑上却有问题
	}
}
class B
{
	A a;  
	public B(A a)
	{
		this.a = a;
	}
}

问题分析,首先,上面的代码,语法上是没有问题的。当add_B()方法被调用的时候,一定是先存在了一个类A的对象a,我们调用该方法,也是想要创建一个类B的对象b,并将b加入到a中去。 但是在如上代码中,实例化了b之后,却又新实例化了一个a0,而不是原来的a,此时的b则是被加入到了新实例化的a0中。与原来的a无关。这样则背离了我们最初的目的。因此需要使用this关键字来实现。代码如下:

class A
{
	B b;
	public void add_B()
	{
		b = new B(this);	//使用this来指明当前对象,即可将a传给b
	}
}
class B
{
	A a;  
	public B(A a)
	{
		this.a = a;
	}
}

d.用于构造方法之间的互相调用
普通函数是通过 对象 . 方法名(参数) 的形式调用的,而构造方法是由编译器自动调用的,我们不能在代码中调用构造方法。那么需要在构造方法中互相调用重载的构造方法,则需要使用this关键字。代码如下:

class Test
{
	public Test()
	{
		this("function2");
	}
	public Test(String m)
	{
		System.out.println(m+" is running");
	}

	public static void main (String arg[])
	{
		Test t = new Test();
	}
}
---------------------------------------
输出结果为:
function2 is running

this()根据参数的不同选择调用不同的重载构造函数,但是,只能使用一次。不能如下书写代码:

class Test
{
	public Test()
	{
		this("function2");
		this("function",3);	//第二次使用this关键字,想调用第三个构造函数
	}
	public Test(String m)
	{
		System.out.println(m+" is running");
	}
	public Test(String m,int n)
	{
		System.out.println(m+n+" is running");
	}

	public static void main (String arg[])
	{
		Test t = new Test();
	}
}

此时,编译器会报错

错误: 对this的调用必须是构造器中的第一个语句
                this("function",3);
                    ^
1 个错误

6.对象的强制类型转换

class A
{
	public void func1()
	{
		System.out.println("A func1 is calling");
	}
		public void func1()
	{
		System.out.println("A func2 is calling");
	}
}

class B extends A
{
	public void func1()
	{
		System.out.println("B func1 is calling");
	}
		public void func3()
	{
		System.out.println("B func3 is calling");
	}
}

class Test
{
	public static void main(String args[])
	{
		B b = new B();
		callA(b);			//将类B传递给callA函数
	}
	public static void callA(A a)		//函数接受一个类A的对象作为参数
	{
		a.func1();
		a.func2();
		a.func3();		//类A中没有func3(),类B中才有,定义函数时接收的是类A,实际传入的是类B。那么,这样写是否会报错呢?
	}
}

上面的代码将在第36行报错,虽然传递给函数callA的参数是类B的一个实例b,确实存在func3(),但是对于编译器来说,它接收的是类A的实例,类A没有func3(),所以编译器会报错。如果去掉第36行,则比啊你要通过,编译器会自动将类B转换成类A。甚至可以在去掉第36行的时候,在第30行后加入如下代码都可以顺利编译:

A a=b;

或者第30行改写成

callA(new B());

都能顺利编译。
说明子类能自动转换成父类。
若想36行代码能执行,则需要强制类型转换,将callA()如下改写即可:

public static void callA(A a)
{
	B b = (B)a;
	b.func1();
	b.func2();
	b.func3();
}

为了安全起见,最好是对传进来的参数进行判断:

public static void callA(A a)
{
	if (a instanceof B)	//判断参数a是不是类B的实例
	{
		B b = (B)a;
		b.func1();
		b.func2();
		b.func3();
	}
	else
	{
		a.func1();
		a.func2();
	}
}

垃圾回收

C++中用于垃圾回收的方法称为析构方法。
Java中finalize()方法用于垃圾回收,该方法继承自Object类,即所有的类都会有该方法。当一个对象变成垃圾后,并不会立即执行该方法。
执行以下代码可以立即清理垃圾。

System.gc();

gc()即garbage collector垃圾回收器。当程序执行了上述代码后,程序才会调用被标记为垃圾的对象的finalize()方法,执行完finalize()方法后,垃圾才会被回收。

关键字

关键字的分类及作用1

访问控制

private
在类A中有使用private修饰的属性或者方法,其他类中无法访问或调用被private修饰的属性或方法,只能是在类A中访问和调用。

protected
public

类、方法、变量修饰符

abstract
class
extend
final
用于修饰类、方法、变量。
当修饰类的时候,类就不能再被继承了。
当修饰变量的时候,变量相当于常量,将不能再被赋值。
当修饰方法时,方法将不能再被覆盖/重载。

implements
interface
native
new

static
1.静态成员变量/方法
当编写好一个类A,只有实例化A的一个对象之后,系统才会分配内存空间给对象,此时才能访问该类实例化出来的对象中的属性或者方法。
当需要在不实例化出对象即可访问该类中的属性或者方法无论有多少个实例对象,该属性或方法在内存中都只有一份,即类中的一个变量为所有的实例对象所共享时,则需要使用static关键字对该属性或者方法进行修饰。经过static修饰的属性或方法在声明的时候,内存即会为其分配一个内存空间。
无对象的情况下访问静态成员的方式有:
a.在类A的内部调用static修饰的属性或者方法时,可以接直使用成员变量名或者方法名类名.属性/方法 的方法。
b.在类A的外部调用static修饰的属性或者方法时,只可以使用类名.属性/方法 的方式调用。
2.静态代码块:
经常用来对类属性的初始化。静态代码块格式:

class AAA
{
	static	//使用static关键字进行声明并用{}将代码括起来
	{
		code	//编写代码
	}
}

静态代码块在类被进行装载的时候才会执行,即使类AAA实例化了多个对象,但静态代码块只会在类被装载时执行一次,之后的实例化对象,都不会再执行静态代码块中的内容。
注意:
1.静态成员方法只能直接调用同个类中的其他静态成员变量,不能直接调用非静态成员变量。
2.静态成员方法不能用任何方式来引用this和super关键字。
3.main()方法是静态的,所以JVM在执行main()方法时,不会创建main()方法所在类的实例对象,因此我们也不能直接访问或调用该类中的其他非静态成员。只有在后面的程序中创建了该类的实例对象后才能访问或调用。

strictfp
synchronized
transient
volatile

程序控制

break
continue
return
do
while
if
else
for
instanceof
switch
case
default

异常处理

try
catch
throw
throws

包相关

import
package

基本类型

boolean
byte
char
double
float
int
long
short
null
true
false

变量引用

super
根据参数调用父类的构造函数。不能与this同时出现在同一个构造函数中。只能作为构造函数的第一句出现。

this
this详解参考前面讲解对象时的第5点内容

void

保留字

goto
在C/C++等语言中,使用goto可以实现程序的跳转,从某些方面来说其提供了一定的方便性,例如,在多重嵌套的循环中,可以直接从内部循环中跳出外层循环。然而,这种跳转却没有任何限制,可以随意的进行,从而打破了正常的程序流程。如果程序中多处使用goto,不仅降低程序的可读性,也会对程序的维护与更新造成影响。
因此,为了避免上述情况,Java语言取消了goto的使用,取而代之的是使用循环标签。但是,为哦了避免程序员自行使用goto带来同样的混乱性,Java语言仍将goto定义为一个关键字,用来限制程序员将goto作为一个标识符来使用,由于是一个从不使用的关键字,故也称为“保留字”。

const
C/C++中,const是一个关键字,用来声明一个变量的值是不可改变的,与goto类似,Java语言也将const定义为关键字,但是却没有任何语法应用,也就是保留字。使用const来作为标识符也是不允许的。2

内部类

内部类又称为嵌套类。
内部类的定义:
1.在类中定义类:

class Outer
{
	int outer_i=100;
	void test()
	{
		Inner in = new Inner();
		in.display();
	}
	class Inner
	{
		void display()
		{
			System.out.println("outer_i="+outer_i);
		}
	}

	public static void main(String args[])
	{
		Outer outer = new Outer();
		outer.test();
	}
}

从代码中可以看出,在内部类Inner中成功地调用了外部类Outer的成员变量outer_i。这是因为,在内部类Inner中保存了一个对外部类Outer的引用变量Outer.this,当内部类中的方法访问某一个变量时,在内部类的方法中找不到,在内部类中也找不到这个变量名,内部类中对this的引用就会通过Outer.this被传递给外部类对象上去。
注意:
外部类不能访问内部类中的成员变量和方法。
使用内部类变成模式的好处:
a.代码紧凑,看起来像是把两个类合成一个类,模块性更强。
b.便于类之间成员变量的访问。(前面讲解this的时候,在讲到容器类与部件类之间参数的互相传递,就很麻烦)
c.若在定义内部类的时候加上static关键字进行修饰,则内部类就变成了外部类,与原来的外部类再无关系。

class A
{
	static class B	//用static修饰之后,B不再是A的内部类,而是与A同级的另外一个类
	{
	}
}

d.如果函数的局部变量(函数形参也是局部变量),内部类的成员变量,外部类的成员变量重名,则需要使用以下方式来指明具体要访问的哪一个变量:

class Outer
{
	private int size;
	static class Inner
	{
		private int size;
		public void doStuff(int size)
		{
			size++;				//引用的是doStuff()函数的size
			this.size++;		//引用的是Inner类的size
			Outer.this.size++;	//引用的是Outer类的size
		}
	}
}

2.在方法中定义类:
内部类不单单是只能在类的内部进行定义,还可以在几个程序块的范围之内进行定义。例如在方法内for循环体内等都可以定义内部类。
在方法中定义的内部类只能访问方法中final类型的变量,但仍可以正常访问外部类中的变量,用final修饰的变量相当于一个常量,它的生命周期超出方法的生命周期。

class Outer
{
	int size=10;
	void test()
	{
		final int x=5;
		class Inner
		{
			void doStuff()
			{
				System.out.println(size);
				System.out.println(x);
			}
		}
		Inner inner = new Inner();
		inner.doStuff();
	}
	
	public static void main(String args[])
	{
		Outer outer = new Outer();
		outer.test();
	}
}

在外部引用内部类:

class Outer
{
	int size=10;
	public class Inner
	{
		public void doStuff()
		{
			System.out.println(++size);
		}
	}
}

class TestInner
{
	public static void main(String args[])
	{
		Outer outer = new Outer();		//需要先实例化出外部类的一个对象
		Outer.Inner inner = outer.new Inner();	//指定是哪一个实例对象,再实例化出这个外部类对象的内部类
		inner.doStuff();
	}
}

类的继承

继承的定义

为了更好地代码复用和简化类的定义,可以使用关键字extends进行类的继承。如果不使用继承去定义一个Person类和一个Student类,代码如下

class Person
{
	public String name;
	public int age;
	public String sex;
}

class Student
{
	public String name;
	public int age;
	public String sex;
	public String school;
	void getInfo()
	{
	}
	void study()
	{
	}
}

会发现Student类和Person类有部分代码是重复的,相同的,为了方便和高效地编写代码,则可以使用继承,如下:

class Person
{
	public String name;
	public int age;
	public String sex;
}

class Student extends Person	//使用关键字extends加上被继承类的类名
{
	public String school;
	void getInfo()
	{
	}
	void study()
	{
	}
}

被继承的类称为父类超类,继承了其他类的类叫做子,在例子中,Person为父类,Student为子类。子类继承了父类中所有的成员变量和成员方法,同时子类拥有自己的成员变量和方法,对父类进行了扩展。如下:

class Person
{
	public String name;
	public int age;
	int height;
	private String sex;

	public void setSex(String Sex)
	{
		sex=Sex;
	}
	public String getSex()
	{
		return sex;
	}
}

class Student extends Person
{
	public String school;
	void getInfo()
	{
		System.out.println(this.name="DRF");
		System.out.println(this.age=18);
		System.out.println(this.height=178);
		System.out.println(this.getSex());
		System.out.println(this.school="UESTC");
	}
	void study()
	{

	}
}

class Test
{
	public static void main(String args[])
	{
		Student stu = new Student();
		stu.setSex("male");
		stu.getInfo();
	}
}

输出结果如下:

DRF
18
178
male
UESTC

注意:
1.Java只支持单继承,不支持多继承,即类B继承了类A,则不能再继承类C。
2.Java支持多层继承,类B继承了类A,类D也可以继承类B。即:

class A
{}
class B extends A	//类B继承类A
{}
class D extends B	//类D继承类B,类D不仅有类A中的成员变量和方法,也有类B所独有而类A没有的成员变量和方法
{}

3.子类不继承父类私有的成员变量和成员方法。
4.子类不继承父类的构造方法。可以在子类的构造方法中使用关键字 super(参数列表) 调用父类的构造方法。
如果子类的构造方法中没有显示地调用父类的构造方法,也没有使用关键字this调用重载的其他构造方法,则在new子类的实例对象时,系统会自动调用父类的无参构造方法

class Person
{
	public String name;
	public int age;

	public Person(String name,int age)	//因为手动编写了构造函数,编译器就不会再自动生成无参的构造函数,这里需要注意!
	{
		this.name=name;
		this.age=age;
	}
}

class Student extends Person
{
	public String school;
	void getInfo()
	{
		System.out.println(this.name);
		System.out.println(this.age);
	}
	public Student()
	{
		super("Victor",15);			//使用super调用父类的构造方法
	}
}

class Test
{
	public static void main(String args[])
	{
		Student stu = new Student();
		stu.getInfo();
	}
}

则输出结果为:

Victor
15

5 . 只要父类和子类在同一目录下即可extends(父类需要先编译出来得到.class文件),两个类可以不在同一个文件中。

子类对象的实例化过程

class Person
{
	public String name = "unknow";
	public int age =-1;
	public Person()
	{
	}
	public Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	void getInfo()
	{
		System.out.println(name);
		System.out.println(age);
	}
}

class Student extends Person
{
	public String school = "unknow";
	public Student()
	{
		super();
	}
	public Student(String name,int age)
	{
		super(name,age);
	}
	public Student(String name,int age,String school)
	{
		this(namde,age);
		
		this.school = school
	}
}

class Test
{
	public static void main(String args[])
	{
		Student stu = new Student("DRF",20,"UESTC");
		stu.getInfo();
	}
}

上述代码第43行实例化对象的过程如下步骤:
1.new产生对象后,在内存中为对象分配空间,并根据代码的初始化赋值对变量进行赋值。
2.绑定子类的构造方法参数,在new对象的时候,会将new时的参数传递到类中的构造方法。即将43行中的参数传递给31行的构造方法。而不是立马执行31行的构造方法。
3.在执行31行构造方法的代码之前,编译器会先检查是否存在this调用,若存在,则调用相应的重载构造方法(被调用的重载构造方法又从步骤2开始执行这些流程)。被调用的重载构造方法执行结束后会回到当前构造方法,当前构造方法则跳到到步骤6。
4.如果没有this函数,则会显式或隐式(第29行即显式地追溯父类构造方法,如果没有写super()语句,则编译器会自动追溯,则称为隐式)地追溯调用父类的构造方法(如果一直没有this调用,则会一直追溯到Object类为止)。父类的构造方法又从步骤2开始按流程执行。父类的构造方法全部执行完后,则会回到子类当前的构造方法。子类构造方法则继续向下执行。
5.子类构造方法执行的时候,先进行实例变量的显式初始化(即当代码执行完第33行,回到当前子类,到第34行时),才进行第22行的显式初始化,然后才开始执行子类构造方法中的代码,即才开始执行第35行
6.执行当前构造方法(不执行含有this和super的语句,因为在前面的步骤已经执行过了)

继承中的函数重载

1.当子类中有与父类相同的函数名时,则子类的函数会覆盖父类的函数。
2.子类中的函数访问权限不能弱于父类的访问权限。
这就是继承中的函数重载。

抽象类

抽象方法: Java中可以创建没有实际功能,只是声明了一下,没有具体代码的方法。该方法具体的实现,可交由子类去重载来实现,这种方法就叫做抽象方法。
抽象类: 包含抽象方法的类就叫做抽象类。
抽象方法和抽象类必须用abstract关键字进行修饰。

abstract class A		//抽象类
{
	abstract int aa(int x,String y);	//抽象方法
	void bb(String x,int y)				//非抽象方法
	{
	}
}

注意:
1.即使方法bb()的方法体中没有任何代码,但仍然不是抽象方法。因为bb()使用了{},{}意思是函数的具体实现。
2.抽象类不能产生实例对象,即不能 new A() ,但是抽象类的子类可以通过覆盖掉父类中的抽象方法从而变成非抽象类,就可以实例化了。

接口

接口的定义与实现
如果一个类中的所有方法都是抽象的,那我们就可以用另外一种方式来定义这个类,那就是接口的定义。
接口是抽象方法和常量的集合,是一种特殊的抽象类。它只能包含常量的定义和方法的声明,不能有变量和方法的实现。

abstract class A
{
	public static final int ID = 1;
	abstract int aa();
	abstract void bb();
}

上述抽象类可以改写成:

interface A
{
	int ID = 1;
	int aa();
	void bb();
}

注意:
1.接口中的成员都是public访问类型的
2.可以定义一个新的接口去extends已有的接口
3.可以使用implements 关键字去实现一个接口中定义的部分方法或全部方法
4.一个类可在继承另一个类的同时实现另外一个接口

interface Runner
{
	int ID = 1;
	void run();
}

interface Fly
{
	void fly();
}

interface Animal extends Runner
{
	void breath();
}

class Cat implements Animal
{
	public void run()		//注意要使用public关键字,因为interface中的方法都是public的
	{
		System.out.println("Cat is running");
	}
	public void breath()
	{
		System.out.println("Miao~");
	}

	public static void main(String args[])
	{
		Cat c = new Cat();
		int j =0;
		j = Runner.ID;		//对接口中常量的访问方法
		j = c.ID;			//该行效果和上一行一样
		j = Cat.ID;

		c.ID = 2;			//错误写法,因为ID是常量,因此不能对其进行赋值修改
	}
}

abstract class WaterAnimal implements Animal	//没有实现所有方法,WaterAnimal类是个抽象类,需要使用abstract关键字修饰
{
	public void breath()
	{
		System.out.println("fish is bubbling");
	}
}

class Bird implements Runner,Fly		//一个类可以实现多个接口
{
	public void run()
	{}
	public void fly()
	{}
}

class Person
{
}

class Student extends Person implements Runner
{
	public void run()
	{
	}
}

注解、注解类

在JDK1.5版本中加入了注解,称为内置注解。自定义的注解称为注解类

@Override			//表示当前的方法定义将覆盖超类中的方法,如果假如该注解,却没有覆盖父类方法,则会有错误提示
@Deprecated			//过时的,使用该注解,编辑器会有告警提示,在API中,有更好的实现方法,现在的方法过时了,被放弃了
@SuppressWarnings 	//压制警告信息,在编辑器中出现告警信息,使用该注解可以压制警告,让编辑器不再出现警告

暂不详细写,改天有时间再细写。3

面向对象三大特性

多态性

1.应用程序不必为每个派生类(子类)编写功能调用,只需要对抽象基类进行调用即可。这叫做“以不变应万变”。可提高程序的可复用性。
2.派生类的功能可以被基类的引用变量引用,这叫做向后兼容。即现在写的程序可调用以后写的程序。可提高程序的可扩充性和可维护性。

接口在面向对象的程序设计与编程中应用非常广泛,举个例子:
电脑主板需要声卡来发出声音和网卡来发送数据,但是主板厂商和声卡厂商,网卡厂商三者互相之间并不认识,并无关系,那声卡和网卡怎么能插地进主板上呢,主板厂商又是怎么知道声卡和网卡卡槽的形状,规格的呢?是因为有PCI在定制标准,PCI定制的标准就相当于接口,它规定了声卡的卡槽形状,规格,也规定了网卡的卡槽和规格。主板厂商从PCI那里了解到了声卡网卡的卡槽形状和参数规格,就可以根据这些标准来设计自己的主板,以便能被声卡和网卡插入。主板厂商也不需要去了解网卡和声卡的具体实现过程,只要为其预留好指定规格的插槽能让卡插进来,体现了多态性的第2点。不管你插进来的是声卡还是网卡,我都已经预留好了相应的卡槽,体现了多态性的第1点。看如下示例代码:

interface PCI
{
	void start();
	void stop();
}

class NetWorkCard implements PCI
{
	public void start()
	{
		System.out.println("Send data ...");
	}
	public void stop()
	{
		System.out.println("Stop Send ...");
	}
}

class SoundCard implements PCI
{
	public void start()
	{
		System.out.println("Du ... Du ...");
	}
	public void stop()
	{
		System.out.println("Stop Du ...");
	}
}

class MainBoard
{
	public void usePCICard(PCI p)
	{
		p.start();
		p.stop();
	}
}

class Assembler
{
	public static void main (String args[])
	{
		MainBoard mb = new MainBoard();
		NetWorkCard nc = new NetWorkCard();
		SoundCard sc = new SoundCard();

		mb.usePCICard(nc);
		mb.usePCICard(sc);

		mb.usePCICard(new PCI(){		//匿名内置类,看下面解析
			public void start()
			{
				System.out.println("Start Card Test");
			}
			public void stop()
			{
				System.out.println("Stop Card Test");
			}
		});
	}
}

匿名内置类 假如主板厂商需要对自己的主板进行测试,无论声卡网卡,只要抓板能正常运行就行,则随便生成的一个用之即抛的测试卡,则可以使用匿名内置类的方式来实现。上述代码第51行的写法等同于:

class A implements PCI
{
	public void start()
	{
		System.out.println("Start Card Test");
	}
	public void stop()
	{
		System.out.println("Stop Card Test");
	}
}
mb.usePCICard(new A());	//这样写的话需要临时定义一个内置类A,当我们连内置类的名称都不想要的时候,则可以使用上面匿名内置类的写法来实现

由于在编写代码的时候,我们已知类A是要实现接口PCI的,所以编写匿名内置类那里,可以直接使用接口PCI,而不需要再麻烦去定义一个类A implements PCI

封装性

前面讲解的,先不总结,懒

继承性

前面讲解的,懒,以后总结

异常处理

先不写,没时间,以后更新

多线程

。。。。慢慢来,不急着写

文件

先不写,丢到高级篇的I/O去写?考虑考虑怎么安排

设计模式

设计模式是在大量的时间和总结后形成的优选的代码结构、编程风格以及解决问题的思考模式。

Java的设计模式大体上分为三大类:4

创建型模式
1.工厂方法模式
2.抽象工厂模式
3.单态模式
4.建造者模式
5.原型模式

结构型模式
1.适配器模式
2.装饰器模式
3.代理模式
4.外观模式
5.桥接模式
6.组合模式
7.享元模式

行为型模式
1.策略模式
2.模板方法模式
3.观察者模式
4.迭代子模式
5.责任链模式
6.命令模式
7.备忘录模式
8.状态模式
9.访问者模式
10.中介者模式
11.解释器模式

单态设计模式

采取一定的方法,在整个程序代码系统中,对某个类只能存在一个实例对象,并且该类只提供一个取得其实例对象的方法。若要让类在JVM中只产生一个实例对象,就必须将类的构造方法修饰为private,这样就不能使用new在类的外部实例化对象了。

Java的反射机制

反射机制5就是将类别的各个组成部分进行剖析,可以得到每个组成部分,就可以对每一部分进行操作。
在比较复杂的程序或框架中来使用反射技术,可以简化代码提高程序的复用性。
反射机制的作用:

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的方法

JNI

原生开发
原生开发语言
Android原生开发语言
安卓是Linux内核,Linux是使用C/C++编写的,故安卓的原生开发语言为C/C++


  1. 关键字部分的分类来自于 https://www.cnblogs.com/AloneZ/p/java1.html ,具体内容根据我自己的理解来写 ↩︎

  2. 摘自 https://blog.csdn.net/u012552052/article/details/44522321 ↩︎

  3. 参考自 https://www.cnblogs.com/huojg-21442/p/7239846.html ↩︎

  4. 参考自 https://www.cnblogs.com/malihe/p/6891920.html ↩︎

  5. 参考自 https://www.cnblogs.com/zhengtu2015/p/5829740.html ↩︎

你可能感兴趣的:(安卓开发笔记,JAVA开发笔记)