Java变量
Java变量类型
基本数据类型:byte short int long float double char boolean
引用数据类型:class interface []
Java变量运算
Java在运算时,如果byte,char,short之间进行运算时,应该用int接收。当小容量的数据类型与容量大的数据类型的变量进行运算时,结果自动提升为容量大的数据类型。
Java的位运算
Java的数据类型强制转换和C++类似
默认情况下常量整型为int,浮点型为double,所以当我们使用long进行赋值超过int的数值时应在后面加l,例如
long num = 222222222l;
String
String属于引用数据类型,不属于基本数据类型,不可以和8种基本数据类型进行运算,但是可以和其进行字符串的连接。
Scanner
可以使用Scanner类获取键盘输入的内容
Java数组
Java一维数组
public class Array{
public static void main(String[] args){
int[] array=new int[]{1,2,3}; // 静态初始化
String[] names=new String[2]; // 动态初始化
names[0]="aaa";
name[1]="bbb";
/*遍历names数组*/
for (int i=0;i<array.length;i++){
System.out.println(array[i]);
}
}
}
数组元素的默认初始化值:
数组元素是整型:0
数组元素是浮点型:0.0
数组元素是char型:0 或 ‘\u0000’ 而非 ‘0’
数组元素是boolean型:false
数组元素是引用数据类型:null
Java一维数组内存解析
JAVA内存结构简单说明
在JAVA中,一维数组的内存情况如下
public class Test{
public static void main(String[] args){
int[] arr = new int[]{1,2,3};//创建一个静态的Int数组,长度为3
//int[] arr={1,2,3}; 这种写法也可以
String[] arr1 = new String[4];//创建一个动态的String数组,长度为4
arr1[1] = "刘德华";//赋值初始化
arr1[2] = "张学友";//赋值初始化
arr1 = new String[3];//将arr1重新声明
}
}
在上述的代码之中,我们首先创建了一个静态的名叫arr的数组,JVM在栈中将创建一个arr的变量并指向其在堆中创建的数组的开头内存地址。接着我们创建了一个动态的名叫arr1的动态数组,JVM在栈中创建了一个arr1变量并将其指向在堆中创建的数组的开头内存地址,然后我们对arr1数组进行赋值,JVM会根据其指向的内存地址进行判断对其赋值,最后我们将创建了一个新的数组并也声明为arr1,这时候JVM会将栈中的arr1的内存地址指向新的在堆中的开头内存地址。这时候我们最先创建的arr1的数组(0X12ab)已经无效,JVM的垃圾回收机制将会在以后的某个时间对其堆内存进行回收。
Java二维数组
JAVA中的二维数组其实也是一维数组,如下图(图中arrA为一维数组,arrB为二维数组)
这时候,二维数组中的一维数组是一个引用数据类型,指向了另外一个一维数组。
public class test {
public static void main(String[] args){
//int[] arr[]=new int[][]{{1,2,3},{4,5},{6,7,8,9}}; 与下面为等价写法
int[] arr[]={{1,2,3},{4,5},{6,7,8,9}};
System.out.println(arr.length);// 这里的length函数与里面有多少个元素无关,这里输出为3
for (int i=0;i< arr.length;i++){
System.out.print(arr[i].length);//输出分别为3 2 4 因为{1,2,3}有3个元素,{4,5}有2个元素,{6,7,8,9}有4个元素
System.out.print(" ");
}
System.out.println();
System.out.println();
/*遍历arr二维数组*/
for (int i=0;i< arr.length;i++){
for (int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]);
System.out.print(" ");
}
System.out.println();
}
}
}
Arrays工具类
JAVA自带的操作数组的工具类,里面定义了很多操作数组的方法
常用Array方法
import java.util.Arrays;
public class test {
public static void main(String[] args){
int[] arr={1,2,4,3};
int[] arr1={1,2,3,4};
int index=Arrays.binarySearch(arr,4);//查找数字为4的元素在数组的第几个
System.out.println(index);//输出index
boolean b=Arrays.equals(arr,arr1);//对比数组是否相等,相等为True,不相等为False
System.out.println(b);//输出结果
Arrays.sort(arr);//进行排序
System.out.println(Arrays.toString(arr));//打印输出数组
Arrays.fill(arr,10);//将数组的所有元素都改写成10
System.out.println(Arrays.toString(arr));//打印输出数组
}
}
更多详细信息请查看官方文档 https://docs.oracle.com/javase/8/docs/api/
类和对象
在Java种我们可以使用class关键字进行类的创建,当我们想要使用类时,对其进行实列化生成对象。
权限的标识符是类的封装性的体现之一,其标识符有以下四种private protected public defalut(缺省)
其访问权限如下表所示:
修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
---|---|---|---|---|
private | √ | |||
defalut(缺省) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
Java的类实例化后,首先会在堆中申请内存,然后在栈中生成一个变量名指向其在堆中的内存地址
匿名对象
匿名对象是指new出一个对象而不对其进行命名,例如
new 类().属性名();
在匿名属性中,两次new出的对象是并无关系的。即每次使用匿名对象后,由于没有其他引用,JVM的垃圾回收机制会自动对其进行回收。
类中进行方法重载
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。
重载规则:
被重载的方法必须改变参数列表(参数个数或类型不一样);
被重载的方法可以改变返回类型;
被重载的方法可以改变访问修饰符;
被重载的方法可以声明新的或更广的检查异常;
方法能够在同一个类中或者在一个子类中被重载。
无法以返回值类型作为重载函数的区分标准。
可变个数的形参
JDK 5.0之后,我们可以使用形容 int … n 声明形参,其类似于一个数组。示例代码:
public class test {
public static void main(String[] args){
new Test1().test(1);
new Test1().test(1,2,3,4,5);
}
}
class Test1{
public void test(int n){
System.out.println("输入类型为int");
}
public void test(short n){
System.out.println("输入类型为short");
}
public void test(double n){
System.out.println("输入类型为double");
}
public void test(int ... n){
for (int i=0;i<n.length;i++){
System.out.println(n[i]);
}
}
}
/*输出结果为
输入类型为int
1
2
3
4
5
*/
注意,String … strs 和 String[] strs 不能重复出现,原因在于在jdk 5.0之前,接受多个参数使用的方法就是后者
构造器
其作用是:定义在java类中的一个用来初始化对象的方法,用new+构造方法,创建一个新的对象,并可以给对象中的实例进行赋值。
JavaBean
JavaBean是一种Java语言写成的可重用组件
JavaBean是指符合以下标准的Java类
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且对应的get、set方法
作用:
用户可以使用JavaBean将功能、处理、值、数据库的访问和其他任何可以用java代码创造的对象进行打包。用户可以认为JavaBean提供了一种随时随地的复制粘贴的功能,而不用关心任何变化。
UML类图
this关键字的使用
this关键字的引入是为了为了解决形参和属性相同时存在的问题。其意思为指向了自己的什么。同时,我们也可以在构造器中使用this,进行在一个类中的一个构造器调用同一个类中的其他构造器。除此之外,我们还可以使用this关键字调用构造器。
super关键字的使用
super理解为:父类的,它可以用来调用:属性,方法,构造器
super调用属性和方法:我们可以在子类的方法或构造器中,通过使用”super.属性“或”super.方法“,显示的调用父类中声明的方法或属性。
super调用构造器
- 可以在子类的构造器中显式的使用”super(形参列表)“的方式,调用父类中声明的指定的构造器
- ”super(形参列表)“的使用,必须声明在子类构造器的首行
- 在类构造器中,”this(形参列表)“ ,”super(形参列表)“ 只能二选一,不能同时出现
- 在构造器的首行没有显式的声明”this(形参列表)“ ,”super(形参列表)“ ,则默认使用super
继承性
继承性的格式:class A extends B{}
子类有父类的所有属性和方法,但是子类无法访问父类的私有属性或方法,子类继承是继承父类的所有东西除了构造函数。
java中关于继承类的规定:
- 一个类可以被多个子类继承
- 一个类只能有一个父类(单继承)
- 子父类是相对的概念
- 子类直接继承的父类称为直接父类,间接继承父类成为间接父类
- 子类继承父类以后,就直接获取父类以及所有间接父类中声明的属性和方法
注意:如果我们没有显式的声明一个类的父类,则此类继承与java.lang.Object类
重写
重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。
重写和重载的区别:
- 重载可以在一个类当中声明多个名字相同,而参数不同的方法,同时构造器也可以重载。而重写是子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作,构造器不能重写。
- 重载不认为表示为多态性,而重写则认为是多态性
多态性
当我们重写方法后,我们就可以使用多态性。
对象的多态性:父类的引用指向子类的对象
多态性如何使用:父类 变量名 = new 子类(形参列表);
多态的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们执行的时子类重写父类的方法
总结:编译看左边,运行看右边
多态性的条件
- 类的继承关系
- 方法的重写
向下转型
在多态性中,无法调用子类特有的方法。这时候我们如果想访问子类中特有的方法,我们就需要使用向下转型。假设Animal是Dog类的父类:
Animal animal = new Animal();
Dog dog = (Dog)Animal;
instanceof关键字
a intanceof A 判断对象a是否为类A的实例。如果是,返回true,如果不是,返回false,为了保证在向下转型时出现ClassCastException的异常,我们使用instanceof关键字。
object类的一些方法重写
equals()
’==‘ 运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型,比较两个变量保存的数据是否相等。(不一定类型相同)
如果比较的是引用数据类型,比较两个对象的内存地址值是否相等。
equals()方法的使用
3. 是一个方法,而非运算符
4. 只能适用于引用数据类型
5. Object类中equals()的定义和’==‘作用相同
6. 像String,Data,File,包装类等都重写了Object类中的equals()的方法,重写后就不再是对比内存地址值,而是比较两个对象的”实体内容“是否相等
在日常使用过程中,我们在自定义类中使用equals()方法通常是为了比较两个对象的“实体内容”是否相等,这时候,我们就要对Object类的equals()进行重写
class Person{
int age;
long id;
public Person(int age,int id){
this.age = age;
this.id = id;
}
//重写equals()方法
public boolean equals(Object obj){
//判断内存地址是否相同
if (this == obj){
return true;
}
if (obj instanceof Person){
Person person = (Person)obj;
if (this.age == person.age && this.id == person.id){
return true;
}
}
return false;
}
}
toString
Object类中toString()的使用
- 当我们输出一个对象的引用时,实际上就是调用了当前对象的toString
- 像String,Data,File,包装类等都重写了toString方法
- 自定义类也可以重写toString的方法
class Person{
int age;
long id;
public Person(int age,int id){
this.age = age;
this.id = id;
}
//重写toString方法
public String toString(){
return "Person[age="+this.age+",id="+this.id+"]";
}
}
Java单元测试
步骤:
- 选中当前工程-右键选择: build path - add libraries - JUnit 4 -下- 步
- 创建Java类,进行单元测试。
此时的Java类要求: ①此类是public的 ②此类提供公共的无参的构造器 - 此类中声明单元测试方法。
此时的单元测试方法:方法的权限是public ,没有返回值,没有形参 - 此单元测试方法上需要声明注解: @Test,并在单元测试类中导入: import org.junit. Test;
- 声明好单元测试方法以后,就可以在方法体内测试相关的代码。
- 写完代码以后,左键双击单元测试方法名,右键: run as - JUnit Test
说明:
- 如果执行结果没有任何异常:绿条
- 如果执行结果出现异常:红条
在实际开发过程中,可以直接使用@test然后点击IDE的错误提示让其进行自动修正
包装类
在Java中,基本数据类型无法体现面向对象,而使用包装类,便可以使其拥有类的特点,调用类中的方法。
在JDK 5.0的时候加入了一个新特点:自动装箱与自动拆箱
//自动装箱:基本数据类型--->包装类
int num2 = 10;
Integer in1 = num2;//自动装箱
boolean b1 = true;
Boolean b2 =b1;//自动装箱
//自动拆箱:包装类--->基本数据类型
System. out. println(in1. toString( ));
int num3 = in1;/ /自动拆箱
基本数据类型、包装类—>String类型调用String重载的valueOf(Xxx xxx)
public void test(){
int num1 =10;
//方式1:连接运算
String str1 = num1 + "";
//方式2:调用String的valueOf(Xxx xXx )
float f1 = 12.3f;
String str2 = String.value0f(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);//"12.4"
}
不论是基本数据类型还是包装类都可以使用方式2
string类型—>基本数据类型、包装类:调用包装类的parseXxx()
String s=new String("123");
int num=Integer.parseInt(s);
Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128到127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了。
Integer m = 1;
Integer n = 1;
System. out. println(m == n);//true
Integer x = 128;
Integer y = 128;
System. out.println(x == y);//false
static
static关键字的使用
- static:静态的
- static可以用来修饰属性,方法,代码块,内部类
使用static修饰属性:静态变量
static修饰属性说明:
- 静态变量随着类的加载而加载
- 静态的变量加载要早于对象的创建
- 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
static类变量储存在方法区中的静态域中
使用static修饰方法:
- 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
- 静态方法中,只能调用静态的方法或属性非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
使用static修饰方法的注意点:在静态的方法内,不能使用this,super关键字。
单例模式
饿汉式
坏处:对象加载时间过长
好处:饿汉式是线程安全的
public class test {
public static void main(String[] args){
Person p = Person.returnP();
Person p1 = Person.returnP();
System.out.println(p==p1);
}
}
class Person{
private Person(){}
private static Person p = new Person();
public static Person returnP(){
return p;
}
}
/*输出结果为
true
*/
懒汉式
好处:延迟对象的创建
坏处:线程不安全
public class test {
public static void main(String[] args){
Person p = Person.returnP();
Person p1 = Person.returnP();
System.out.println(p==p1);
}
}
class Person{
private Person(){
}
private static Person p = null;
public static Person returnP(){
if (p == null){
p = new Person();
}
return p;
}
}
使用场景:
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方
式来解决。
- 网站的计数器
- 应用程序的日志文件
- 数据库连接池
- 读取配置文件的类
代码块
- 代码块的作用:用来初始化类、对象
- 代码块如果有修饰的话,只能使用static
分类:静态代码块,非静态代码块
静态代码块
内部可以有输出语句
随着类的加载而执行,而且只执行一次
作用:初始化类的信息
如果一个类定义了多个静态代码块,安声明先后顺序执行
非静态代码块
内部可以有输出语句
随着对象的创建而执行
每创建一个对象, 就执行一次非静态代码块
开发过程中使用代码块的情况:当我们需要一些创建对象时只能执行一次的操作都可以使用静态代码块,例如数据库连接池的开发
final关键字
final :最终的
- final可以用来修饰的结构: 类、方法、变量
- final 用来修饰一个类:此类不能被其他类所继承。比如: String类、 System类、StringBuffer类
- final用来修饰方法:表明此方法不可以被重写。比如Object的getClass
- final修饰变量:此时的“变量”就称为常量
抽象类
abstract关键字的使用
- abstract :抽象的
- abstract可以用来修饰的结构:类、方法
- abstract修饰类:抽象类,此类不能实例化,且抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程),开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
- abstract修饰方法: 抽象方法
抽象方法只有方法的声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类, 需要使用abstract修饰
应用场景:父类不需要直接调用,子类会对其进行重写
接口
编写使用接口与类非常的相似但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
接口的使用
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:定义接口中的成员
3.1 JDK7及以前:只能定义全局常量和抽象方法
全局常量: public static final的 .但是书写时,可以省略不写
抽象方法: public abstract的
3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
4.接口中不能定义构造器的!意味着接口不可以实例化
5. Java开发中,接口通过让类去实现( impl ements )的方式来使用,如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化,如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
6. Java类可以实现多个接口 —> 弥补了Java单继承性的局限性格式: class AA extends BB implements CC,DD,EE。
7.接口与接口之间可以继承,而且可以多继承
在Java8中,接口还要一些新特性:
- 接口中的静态方法,只能通过接口调用
- 通过实现类的对象,可以调用接口中的默认方法
- 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法
- 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写的情况下报错。
代理模式
代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
public class test {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface Network{
void browse();
}
class Server implements Network{
public void browse(){
System.out.println("真实服务器浏览");
}
}
class ProxyServer implements Network {
private Network network;
public ProxyServer(Network network){
this.network = network;
}
void check(){
System.out.println("联网前检查");
}
@Override
public void browse() {
check();
network.browse();
}
}
代理模式的应用场景:
- 安全代理
- 远程代理
- 延迟加载
工厂模式
简单工厂模式
该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。
例如,我们需要创建苹果手机和小米手机,这时候我们可以建立一个工厂生产苹果手机和小米手机。
缺点:增加新功能时,需要修改代码,违反开闭原则
工厂方法模式
这时候我们先常见一个工厂接口,再创建2个工厂分别为苹果手机工厂和小米手机工厂,当我们要生成手机时,使用对应的工厂进行生成。
抽象工厂模式
抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
而且使用抽象工厂模式还要满足一下条件:
1.系统中有多个产品族,而系统一次只可能消费其中一族产品。
2.同属于同一个产品族的产品以其使用。
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
1.Java中 允许将-一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2.内部类的分类:成员内部类(静态、非静态) Vs 局部内部类(方法内、代码块内、构造器内)
3.成员内部类:一方面,作为外部类的成员:调用外部类的结构,可以被static修饰,可以被四种不同权限修饰。另一方面,作为一个类:类内可以定义属性、方法、构造器等,可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承,可以被abstract修饰