在学习Java的前期看了一部分郝斌老师的Java学习教程视频,当时做了一些笔记,现在将这些笔记整理到这里,也当是边整理边复习。
Java与C/C++不同的部分特点
1、Java摒弃了C/C++中容易引发程序错误并且难以掌握的一些特性,如指针、结构以及内存管理等。
2、Java安全性比C/C++高,原因如下:
1.Java是一种强类型语言,类型检查比C/C++还要严格(例如写int i=6.6会报错)
2.提供垃圾回收机制,有效避免内存泄漏问题
3.禁止非法内存访问,无授权情况下不能访问内存
3、Java中double和float的输出控制符都是用%f表示
4、Java的默认访问修饰符是default,使用public和protected修饰的成员可以在外部访问,使用private修饰的成员不能在外部访问
Java虚拟机
虚拟机不是硬件,是软件式的
将通用的应用程序通过特定的java虚拟机软件最终编译/解析成特定的机器的指令
在不同的机器上装有特定的Java虚拟机
标识符
1、标识符是以字母,下划线,美元符($)开始,后面可以跟字母,下划线,美元符,数字的一个字符序列
合法的标识符:identifier,userName,User_Name,$change
非法的标识符:2mail (以数字开头),room# (标识符仅可以使用字母、下划线、美元符、数字,字符 '#' 非法),class (class是Java的关键字,不能作为标识符使用)
2、Java的数据类型:
基本数据类型:
整数类型:byte,short,int,long
浮点类型:float,double
字符型:char
布尔型:boolean
引用数据类型:
类:class
接口:interface
数组
3、输出控制符:
%x/%X:用十六制形式输出(区别是字母的大小写之分)
%#x/%#X:用十六进制形式输出且前面会加上0x或0X
4、一个常量整数默认是int类型,如果数字过大,则必须在末尾加L,否则会报错!
例:
long i=9223372036854775807; //error
long i=9223372036854775807L; //accpet
5、一个实数默认是double类型,如果希望实数是float类型,可以在后面加f/F
将double类型数值赋给float会报错
例:
float x=2.2;//error
float x=2.2f;//OK
6、Java中字符和字符串都用Unicode编码表示,一个字符是占两个字节
7、布尔类型:
用boolean表示,不能写成bool,且不能对boolean类型进行类型转换
布尔型数据只有true和false,不对应于任何整数值
定义如:boolen b=true;
布尔型数据只能参与逻辑关系运算(&&, ||, ==, !=, !)
注意:if,while,for中进行真假判断时只能使用逻辑表达式
7、不同类型变量存储范围:
8、数据类型转换:
byte b=10;
int i=6;
i=b; //accept
b=i; //error
b=(byte)I; //accept(强制类型转换)
之后的i仍然是int类型,并没有转换为byte类型,(byte)i产生了一个临时数据,并没有改变i本身的数据类型
9、算术运算符:
+:
System.out.println('a'+1); //输出98
System.out.println(""+'a'+1); //输出a1
右移>>:右移之后最高位补上原符号位
右移>>>:右移之后最高位都补0
<<和<<<一样
内存分配
设A是一个类
A aa=new A();
解读:
new后的A()部分是在堆(heap)中
aa是局部变量,指向在堆中动态申请的A对象,aa本身的内存是由栈(stack)中分配得到的
一个对象只含有属性的空间,n个对象公用一份方法的拷贝
static
1、多个对象公用一个static属性
2、static属性属于类本身,没有对象,仍然可以直接用类名来调用static属性,当然也可以通过类对象来调用
3、只有非private的static成员才可以通过类名的方式访问,static只是表明了该成员具有可以通过类名访问的潜在特性,但是否可以通过类名访问,仍然需要该成员是非private的
4、非static方法可以访问static方法以及static成员,但是static方法不能访问非static方法(非static属性也不行——例如类内的非static数据成员),这是因为对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象
5、静态方法不能以任何方式引用this和super关键字,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this所引用的对象根本就没有产生
static的实际应用:
1、求出当前类的对象个数:
通过让类有一个静态属性(数据成员),每一次调用类的构造方法就让该数据+1,并有一个static方法来获得该静态属性数据,通过类名调用该static方法就可以获知当前对象个数。(个人感觉应该得在析构方法有让该数据-1的操作,以便释放时候数量会减少)
class A
{
private int i;
private static int cnt = 0;
public A()
{
cnt++;
}
public A(int i)
{
this.i=i;
cnt++;
}
public static int getCnt()
{
return cnt;
}
}
2、限定一个类只能有一个对象
将构造方法写为私有,且让一个类对象作为类的属性之一(注意得是static,因为要被static方法访问),并通过一个static成员方法来访问这个类对象
class A
{
private int i;
private static A aa = new A(); //aa是A对象的属性
private A(){}
public static A getA() //static一定不能省略
{
return aa;
}
}
继承
Java只支持单继承,不支持多重继承。即一个类只能有一个父类,不能有多个父类。
子类可以继承父类所有成员变量和成员方法,但子类永远无法继承父类的构造方法。在子类的构造方法中可使用语句super(参数列表)调用父类的构造方法,而不是直接写父类的类名,这与C++不同
使用super来调用父类的构造方法:
class A{
public int a;
public int b;
public A(int a,int b){
this.a=a;
this.b=b;
}
}
class B extends A{
public int k;
public B(int i,int j,int k){
//A(i,j); //error
super(i,j);
this.k=k;
}
}
注意:
1、对super的调用必须在构造方法中,且必须是构造方法中的第一个语句
2、如果父类中没有无需参数的构造方法,则子类的构造方法中必须写出对应的带参数的super方法,不然会默认调用不带参数的super()方法,而在父类中找不到对应构造方法,则会报错
3、一个子类的任何一个构造方法中都只能出现一个super方法
调用父类的同名方法:
例如父类和子类都有方法f(),在子类中调用父类的f(),写法:super.f();
在子类中重写父类中已有的方法:
1、重写方法必须和被重写方法具有相同的方法名、参数列表和返回值类型
2、子类中不允许出现于父类同名同参但不同返回值的方法
3、子类的同名方法不能比父类中被覆盖的方法有着更严格的访问权限(例如父类中是public,子类中是protected)
假设A类是父类,B类是子类,a,b分别是类A和B的对象,则赋值a=b是正确的,b=a是错误的
理解:子类具有父类的特性,子类可以当做父类来看待,例如动物是父类,狗是子类,那么狗可以当做动物来看待,但是动物不可以当做狗来看待
(注意:java中类的对象其实就是一个指针指向这个对象,所以上面的这些也可以跟C++继承中父类和子类的指针赋值一样去理解,即是把bb对象的地址发送给aa这个指针)
多态
多态:一个父类的引用类型变量它既可以指向父类对象也可以指向子类对象,它可以根据当前时刻指向的不同,自动调用不同对象的方法。
作用:同一段代码做不同事情
A为父类,B为子类,类A和B都有成员方法f(),a和b分别是类A和类B的对象,如果指令a=b,则调用a.f()时候,调用的是类B中的f方法,如果类B中有方法g()而类A中没有,那么调用a.g()是错误的。总而言之就是java默认父类和子类的相同方法是virtual型的,调用时候会触发多态,通过父类指针调用子类方法,不可以调用父类中不存在而子类中存在的方法
多态注意事项:
1、通过父类引用只能访问子类对象从父类继承过来的成员
2、通过父类引用不能访问子类对象所特有的成员
3、父类引用永远不可能直接赋给子类引用(只有在父类引用本身指向的是一个子类对象时,才可以把父类引用强制转化为子类引用,其他情况下不允许把父类引用强制转化为子类引用,否则运行时会出错)
抽象
abstract class A //抽象类
{
abstract public void f();
//没有方法体的方法叫做抽象方法
}
抽象方法:
1、在定义Java方法时可以只给出方法头,而不给出方法内部实现代码,这样的方法称为抽象方法
2、凡是没有方法体的方法必须使用关键字abstract修饰为抽象方法
3、凡是含有抽象方法的类都必须声明为抽象类
抽象类:
1、用abstract关键字来修饰一个类时,该类叫做抽象类
2、包含抽象方法的类必须声明为抽象类
3、抽象类不一定有抽象方法
4、有抽象方法的一定是抽象类
5、可以定义一个抽象类的引用,但是不可以定义一个抽象类的对象(例如A是抽象类,A aa;是对的,A aa=new A();是错误的)
final
final可以修饰:整个类、类中的若干个属性、类中的若干个方法
final修饰整个类:表示该类不能被继承
final public class A {……}
final和public的位置可以互换
final修饰类中的若干个属性:表示属性必须被赋值并且只能被赋一次值(类似于const)
初始化方式有两种且只能选择其中一种:
1、在定义成员变量同时初始化
2、在类中所有的构造函数中初始化
注意:一个类的所有普通方法内部都不可以修改final修饰过的成员变量的值
final修饰类中的若干个方法:表示该方法可以被子类继承,但是不可以被子类重写
接口
接口的定义:
抽象方法和常量值的集合。从本质上讲,接口是一种特殊的抽象类
接口的格式(方括号表示可选)
[public] interface interfaceName [extends SuperInterfaceList]
{
... //常量的定义和方法定义
}
接口中定义的属性必须是public static final的,而接口中定义的方法则必须是public abstract的,因此这些修饰符可以部分或全部省略
同时在实现接口的类中方法的定义也必须是public
例:
interface It
{
int i=20; //正确
void f(); //正确
void g(){} //Error 接口不能含有具体实现的方法
}
实际上的声明:
interface It
{
public static final int i=20;
public abstract void f();
}
class A implements It {
public void f(){} //正确
void f(){} //Error
}
接口中定义的属性的值在实现类中不能被更改
一个类只能实现某个接口,不能继承某个接口,但接口可以继承接口
例:
class A extends It {}
//Error 类只能继承类,不能继承接口,所以接口只能近似当做是抽象类,和类还是有区分
class B implements It {} //Error,因为It接口中含有抽象函数
abstract class C implements It {} //正确
class D implements It {
public void f(){ //这里记得即便接口It中的方法前面没写public,实现的类中也需要加上public字眼,不然会报错
// i = 99; //若加上这句话则Error,因为i是final
System.out.printf("i=%d\n",i);
}
} //正确,因为重写了It接口中的抽象方法
接口不但可以继承接口,而且可以继承多个接口,即接口允许多继承
例:
interface It1{}
interface It2{}
interface It3 extends It1, It2{}
如果一个类只实现了一个接口的部分方法,则该类必须声明为抽象类
一个类可以在继承一个父类的同时实现一个或多个接口,但extands关键字必须在implements之前
class T extends A implements It1,It2{}
不可以new接口对象,但可以定义一个接口引用类型的变量并将其指向实现接口的对象,达到多态目的
接口的作用:
1、通过接口可以实现不相关类的相同行为(如Java规定所有可以完成自我复制功能的类都必须得实现java.lang.Colneable接口,但该接口却是空的,该接口中没有任何内容,目的只是为了起个标志作用)
2、接口提供了不同对象进行协作的平台(例如事件处理)
3、接口可以实现多继承,从一定程度上弥补了类只能单继承的缺陷
4、接口是我们了解一个类功能的重要途径(如Java整个容器框架就是以接口的方式建立起来的,实现不同接口的类完成的是不同的功能,接口使我们了解一个类功能的重要途径)
接口与抽象类的区别:
1、接口中的方法不允许有方法体,但抽象类允许
2、Java类不允许多继承,接口允许多继承
1)接口可以实现多继承,即一个接口可以有多个父类
2)Java只允许单继承,即一个类只能有一个父类