提起Java,首先需要搞清楚两个概念:
- 什么是JDK?
JDK,即Java Development Kit(Java开发工具包)。可以这么理解:JDK = JRE + 开发工具集(如将Java代码编译为字节码文件的Javac)。
- 什么是JRE?
JRE,即Java Runtime Environment(Java运行环境),它是Java程序运行的基础。JRE = JVM(Java Virtual Machine,Java虚拟机) + Java SE标准类库。
1.2 环境安装 关于Java的安装教程此处就不再赘述了(网上教程一大把),这里稍微提一下环境变量。
以windows系统为例,我们在配置环境变量时,分为用户变量和系统变量。如果你将JAVA_HOME配置在系统变量中,那么任何使用这台电脑的用户都可以使用该变量,反之,如果你配置在用户变量中,那么就只有当前用户才可以使用该变量。
环境变量配置完成后,win+x 后按c打开cmd,依次输入javac、java,打印如下内容证明安装成功:
1.3 HelloWorld 下面,我们编写第一个Java程序——HelloWorld:
public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello World!"); } }
将上述代码保存到HelloWorld.java中,打开cmd进入当前目录,执行javac HelloWorld.java,该命令会将你的Java代码编译为字节码文件,再执行java HelloWorld命令以运行程序。
1.4 Java注释Java中分为单行注释和多行注释:
-
单行注释
//这是单行注释
-
多行注释:
-
关键字,即被Java语言赋予了特殊含义,用做专门用途的字符串。
具体Java关键字如下:
-
保留字:现在尚未使用,以后可能会作为关键字的字符串。
goto、const
-
标识符:凡是可以自己起名字的地方都叫标识符。类名、变量名以及方法名都被称为标识符。
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
-
建议:
- 标识符尽量为有意义的单词;
- 包名:全小写。如:aaabbbccc;
- 类名、接口名:每个单词首字母大写。如:MyClass;
- 变量名、方法名:第一个单词首字母小写,之后的单词首字母大写。如:xxxYyyZzz
- 常量名:所有字母都大写,多个单词时使用下划线连接。
Java数据类型分为基本数据类型和引用数据类型。
8种基本数据类型如下:
- 整型:byte(1字节=8bit) short(2字节) int(4字节) long(8字节)
- byte范围:-128 ~ 127
- 声明long型变量,必须以"l"或"L"结尾
- 通常,定义整型变量时,使用int型。
- 整型的常量,默认类型是:int型
- 浮点型:float(4字节) double(8字节)
- 浮点型,表示带小数点的数值
- float表示数值的范围比long还大
- 定义float类型变量时,变量要以"f"或"F"结尾
- 通常,定义浮点型变量时,使用double型。
- 浮点型的常量,默认类型为:double
- 字符型:char (1字符=2字节)
- 定义char型变量,通常使用一对’’,内部只能写一个字符
- 表示方式:
- 声明一个字符
- 转义字符
- 直接使用 Unicode 值来表示字符型常量
- 布尔型:boolean
- 只能取两个值之一:true 、 false
- 常常在条件判断、循环结构中使用
引用数据类型如下:
1. 类 2. 接口 3. 数组
特别地,String和数组均为引用数据类型!
1.7 自动类型转换 当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型。
byte 、char 、short --> int --> long --> float --> double
特别的:当byte、char、short三种类型的变量做运算时,结果为int型
说明:此时的容量大小指的是,表示数的范围的大和小。比如:float容量要大于long的容量
所有数字在计算机底层都使用二进制补码存放。
1.9 运算符-
A instanceof B:判断A是否为B的实例。
-
位运算符:
-
位运算符 *** 作的都是整型的数据
-
<< :在一定范围内,每向左移1位,相当于 * 2
-
>> :在一定范围内,每向右移1位,相当于 / 2
-
-
数组的声明与初始化
//一维数组 int[] ids;//声明 ids = new int[]{1001,1002,1003,1004}; String[] names = new String[5]; int[] arr4 = {1,2,3,4,5};//类型推断 //二维数组 //静态初始化 int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}}; //动态初始化1 String[][] arr2 = new String[3][2]; //动态初始化2 String[][] arr3 = new String[3][]; //也是正确的写法: int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}}; int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};//类型推断
-
一维数组的内存解析:
-
二维数组的内存解析
-
Arrays:提供了很多 *** 作数组的方法:
- equals(int[] a,int[] b):判断两个数组是否相等。
- toString(int[] a):输出数组信息。
- fill(int[] a,int val):将指定值填充到数组之中。
- sort(int[] a):对数组进行排序。
- binarySearch(int[] a,int key):在数组a中查找key并返回索引。
首先,我们一起来理解一下面向对象与面向过程。
所谓面向过程,强调的是功能行为,以函数为最小单位,关注的是“怎么做”。而面向对象,强调的是具备功能的对象,以类、对象为最小单位,关注“由谁去做”。
类是对一类事物的抽象,对象是类实例化后的个体。
-
对象内存解析
-
JVM内存结构
我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。即要将字节码文件对应的类加载到内存中,涉及到内存解析。
- 虚拟机栈,即为平时提到的栈结构。我们将局部变量存储在栈结构中
- 堆,我们将new出来的结构(比如:数组、对象)加载在对空间中。对象的属性(非static的)加载在堆空间中。
- 方法区:类的加载信息、常量池、静态域(类的static属性存放在静态域中)
-
权限修饰符
封装,即隐藏对象内部的复杂性,只对外公开接口。比如:将类的属性私有,同时提供公共的get、set方法设置该属性的值。
类内使用this时,this不能访问static属性。
1.11.2 继承 继承(extends),Java中的类具有单继承性:一个类只能有一个父类。一旦子类A继承了父类B后,A就获取了B中的所有属性和方法。不过,对于B的私有属性,A不能直接访问。
在Java中,所有类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类。
子类继承父类后,就可以对父类中的方法进行重写,重写的规则如下:
- 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同(方法名和形参列表相同)。
- 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符(权限修饰符要大于、等于父类中的修饰符)。权限从小到大顺序为:private < 缺省 < protected < public
- 特殊情况:子类不能重写父类中声明为private权限的方法
- 返回值类型:
- 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void。(void还是void)
- 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类。(引用类型扩展到了子类)
- 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)。(基本数据类型不变)
- 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。(异常不比父类的大)
问题来了,在重写时,父类有一个static方法say1,子类有一个非static方法say1,算不算重写?
emm…,根本不存在这种情况好伐。。。下面实际 *** 作看看:
如图,idea表示“不服”:Main2中的实例方法say()不能重写父类Main1中的静态方法say()。所以,要实现重写,子类和父类的say()方法要么都被static修饰,要么都不被static修饰。
super关键字
1. 在子类中可以使用`super.属性名`的方式获取父类的属性(private属性除外); 2. 在子类中可以使用`super.方法名()`调用父类中的方法(包括被重写的方法)。 3. 在子类构造方法中可以使用super()初始化一个父类对象(该语句必须放在子类构造方法的第一行)。如果没有显式地调用super(),则默认会调用父类中空参的构造器super()1.11.3 多态
多态,父类的引用指向子类的对象(或子类的对象赋给父类的引用),多态是运行时行为。
多态性使用前提:
- 类的继承关系
- 方法的重写
多态的体现:
- 抽象类、接口的使用(JDBC *** 作数据库)
- …
final可以修饰类、变量、方法。
- final修饰类,该类不能被继承;
- final修饰变量,该变量不能被重写赋值;
- final修饰方法,该方法不能被重写,但是可以重载。
abstract可以修饰类、方法。
- abstract修饰类(抽象类),该类不能被实例化。
- abstract修饰方法(抽象方法),该方法只是方法的声明,没有方法体。如public abstract void say();
- 包含抽象方法的类,一定是抽象类。但是抽象类中可以没有抽象方法。
- 只有子类重写了父类中的所有抽象方法后,才能实例化;否则,该子类也是一个抽象类。
- abstract不能用来修饰私方法、静态方法、final的方法、final的类。
- abstract不能用来修饰:属性、构造器等结构
模板方法的设计模式
-
解决问题:
在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
-
代码:
abstract class Template{ //计算某段代码执行所需要花费的时间 public void spendTime(){ long start = System.currentTimeMillis(); this.code();//不确定的部分、易变的部分 long end = System.currentTimeMillis(); System.out.println("花费的时间为:" + (end - start)); } public abstract void code(); } class SubTemplate extends Template{ @Override public void code() { for(int i = 2;i <= 1000;i++){ boolean isFlag = true; for(int j = 2;j <= Math.sqrt(i);j++){ if(i % j == 0){ isFlag = false; break; } } if(isFlag){ System.out.println(i); } } } }
接口,实际上可以看做是一种规范(面向接口编程)。
接口中的成员:
-
JDK7及以前:只能定义全局常量和抽象方法。
- 全局常量:public static final (但是书写时,可以省略不写。)
- 抽象方法:public abstract
-
JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法。
-
接口中定义的静态方法,只能通过接口来调用。
-
通过实现类的对象,可以调用接口中的默认方法。
-
如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。
-
如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没重写此方法的情况下,会报错(接口冲突)。
-
如何在子类(或实现类)的方法中调用父类、接口中被重写的方法?
public void myMethod(){ method();//调用自己定义的重写的方法 super.method();//调用的是父类中声明的 //调用接口中的默认方法 InterfaceA.super.method(); InterfaceB.super.method(); }
-
-
静态代理:实质就是使代理类和被代理类实现同一个接口,然后在代理类中添加其他 *** 作。
-
MyProxy.java文件
package cn.qujialin.proxy; //代理类 public class MyProxy implements Operator{ private Operator operator; public MyProxy(Operator operator){ this.operator = operator; } @Override public int add(int i, int j) { System.out.println("proxy前"); operator.add(i,j); System.out.println("proxy后"); return 0; } @Override public int sub(int i, int j) { System.out.println("proxy前"); operator.sub(i,j); System.out.println("proxy后"); return 0; } @Override public int mul(int i, int j) { System.out.println("proxy前"); operator.mul(i,j); System.out.println("proxy后"); return 0; } @Override public int div(int i, int j) { System.out.println("proxy前"); operator.div(i,j); System.out.println("proxy后"); return 0; } } //被代理类 class MyOperator implements Operator{ @Override public int add(int i, int j){ System.out.println("add......"); return i + j; } @Override public int sub(int i, int j){ System.out.println("sub......"); return i - j; } @Override public int mul(int i, int j){ System.out.println("mul......"); return i * j; } @Override public int div(int i, int j){ System.out.println("div......"); return i / j; } }
-
Operato.java
package cn.qujialin.proxy; //接口 public interface Operator { public int add(int i, int j); public int sub(int i, int j); public int mul(int i, int j); public int div(int i, int j); }
-
TestMain.java
package cn.qujialin.proxy; //测试 public class TestMain { public static void main(String[] args) { Operator op = new MyProxy(new MyOperator()); op.add(1,2); } }
-
-
动态代理
-
MyActiveProxyFactory.java
package cn.qujialin.activeproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //代理工厂 public class MyActiveProxyFactory { public static Object getProxyInstance(Operator op){ Object proxy = null; ClassLoader cl = op.getClass().getClassLoader(); Class[] interfaces = op.getClass().getInterfaces(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); System.out.println("methodName:::" + methodName); Object result = method.invoke(op, args); System.out.println("methodName:::" + methodName); return result; } }; return Proxy.newProxyInstance(cl,interfaces,invocationHandler); } }
-
Operator.java
package cn.qujialin.activeproxy; //接口 public interface Operator { public int add(int i, int j); public int sub(int i, int j); public int mul(int i, int j); public int div(int i, int j); }
-
MyOperator.java
package cn.qujialin.activeproxy; import cn.qujialin.activeproxy.Operator; //被代理类 public class MyOperator implements Operator{ @Override public int add(int i, int j){ System.out.println("add......"); return i + j; } @Override public int sub(int i, int j){ System.out.println("sub......"); return i - j; } @Override public int mul(int i, int j){ System.out.println("mul......"); return i * j; } @Override public int div(int i, int j){ System.out.println("div......"); return i / j; } }
-
TestMain.java
package cn.qujialin.activeproxy; //测试 public class TestMain { public static void main(String[] args) { Operator p = (Operator)MyActiveProxyFactory.getProxyInstance(new MyOperator()); p.add(3,5); } }
-
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类。
内部类的分类:
-
成员内部类(静态、非静态 )
一方面,作为外部类的成员:
-
调用外部类的结构
-
可以被static修饰
-
可以被4种不同的权限修饰
另一方面,作为一个类:
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。
- 可以被abstract修饰
实例化成员内部类:
//创建静态的Dog内部类的实例(静态的成员内部类): Person.Dog dog = new Person.Dog(); //创建非静态的Bird内部类的实例(非静态的成员内部类): //Person.Bird bird = new Person.Bird();//错误的 Person p = new Person(); Person.Bird bird = p.new Bird();
在成员内部类中调用外部类的结构:
class Person{ String name = "小明"; public void eat(){ } //非静态成员内部类 class Bird{ String name = "杜鹃"; public void display(String name){ System.out.println(name);//方法的形参 System.out.println(this.name);//内部类的属性 System.out.println(Person.this.name);//外部类的属性 //Person.this.eat(); } } }
字节码文件格式:外部类$内部类名.class
-
-
局部内部类(方法内、代码块内、构造器内)
在局部内部类的方法中,如果需要调用声明局部内部类的方法中的局部变量,则此局部变量必须声明为final。
- jdk 7及之前版本:要求此局部变量显式的声明为final的
- jdk 8及之后的版本:可以省略final的声明
字节码文件格式:外部类$数字 内部类名.class
异常关系图:
异常处理方式:
- try-catch-finally:finally中的语句一定会被执行(即使try或cattch中含有return语句)。
- throws:只是将异常抛给了方法的调用者,并没真正将异常处理掉。
自定义异常类:
- 继承于现的异常结构:RuntimeException 、Exception
- 提供全局常量:serialVersionUID
- 提供重载的构造器
public class MyException extends Exception{ static final long serialVersionUID = -7034897193246939L; public MyException(){ } public MyException(String msg){ super(msg); } }
你学会了吗?收藏点赞加关注,技术学习不迷路~
微信搜索“五维星空”关注我吧~
by 五维星空-分享前后端技术
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)