Java语言的关键术语:
- 简单性
- 面向对象
- 分布式
- 健壮性
- 安全性
- 体系结构中立
- 可移植性
- 解释型
- 高性能
- 多线程
- 动态性
评价一份代码的好坏
- 代码结构可以重用,提供的是一个中间独立的支持
- 结构性合理、适合维护、可重用性很高
类与对象
面向对象设计的三个主要特征:
- 封装性:内部的操作对外部不可见,当内部的操作都不可直接使用的时候才最安全;
- 继承性:在已有结构的基础上继续进行功能的扩充;
- 多态性:是在继承性的基础上扩充而来的概念,指的是类型的转换处理;
面向对象开发的三个步骤:
- OOA:面向对象分析;
- OOD:面向对象设计;
- OOP:面向对象编程;
类是对某一类事务的共性的抽象的描述,而对象描述的是一个具体的产物。
类的组成:
- 成员属性(Field):简称属性
- 操作方法(Method):定义对象具有的行为
定义类的关键字 => class => 属性+方法
语法格式产生对象:
- 声明并实例化对象:类名称 对象名称 = new 类名称()
- 分步骤完成:
- 1、声明对象 :类名称 对象名称
- 2、实例化对象:对象名称 = new 类名称()
内存分析:
- 堆内存:保存的是对象的具体信息,在程序之中堆内存的开辟是通过关键字new实现的
- 栈内存:保存的是一块堆内存的地址,即通过地址找到堆内存,而后找到对象内容
对象引用传递:两个栈内存地址指向同一个堆内存空间
垃圾空间:没有任何栈内存所指向的堆内存空间,所有的垃圾将被GC(Garbage Collector,垃圾收集器)不定期进行回收,并且释放无用内存。如果垃圾过多,一定会影响GC的处理性能,从而降低整体的程序性能。
一个栈内存只能保存一个堆内存的地址数据。
成员属性的封装:
- 设置或取得属性可以使用setXXX()、getXXX()方法
- 类中所有属性都必须使用private封装
构造方法的定义要求:
- 构造方法名称必须与类名称保持一致;
- 构造方法不允许设置任何的返回值类型,即没有返回值定义;
- 构造方法是在使用关键字new实例化对象的时候自动调用的;
一个类至少存在有一个构造方法,永恒存在。
对象产生格式:
- 定义对象的名称:类名称 对象名称 = null
- 实例化对象:对象名称 = new 类名称()
this关键字
使用描述:
- 当前类中的属性:this.属性
- 当前类中的方法(普通方法、构造方法):this()、this.方法名称()
- 描述当前对象
this实现方法的调用:
- 构造方法调用(this()):使用关键字new实例化对象的时候才会调用构造方法,调用时必须放在构造方法的首行
- 普通方法调用(this.方法名称()):实例化对象产生之后就可以调用普通方法
简单java类
指的是可以描述某一类信息的程序类
核心开发结构如下:
- 类名称一定要有意义,可以明确的描述某一类事物;
- 类之中的所有属性都必须使用private进行封装,同时封装后的属性必须要提供有setter、getter方法;
- 类之中可以提供有无数多个构造方法,但是必须要保留有无参构造方法;
- 类之中不允许出现任何的输出语句,所有内容的获取必须返回;
- 可以提供有一个获取对象详细信息的方法,该方法可以定义为getInfo()方法;
static关键字
定义属性:定义的属性为公共属性,该类定义的所有对象的公共属性都是相同的。static定义的公共属性应该通过所有对象的最高代表(类)来进行访问,即static属性由类名称直接调用。
类名称.公共属性 = ???
static属性并不受到实例化对象的控制。不能使用this关键字对static属性进行修改。
定义方法:可以在没有实例化的情况下使用。
- static方法只允许调用static属性或static方法;
- 非static方法允许调用static属性或static方法;
代码块
-
普通代码块:结构拆分,防止相同变量名称所带来的的互相影响;
-
构造代码块:定义在一个类中,构造块优先于构造方法执行,并且每一次实例化新对象都会调用构造块中的代码;
-
静态代码块:主要指的是使用static关键字定义的代码块
- 主类中定义静态块
- 非主类中定义静态块
静态代码块优先于构造代码块和主方法执行,实例化中仅执行一次,主要目的是为了类中的静态属性初始化;
-
同步代码块(多线程使用)
案例分析
package Java_Learn;
class Address {
private String country;
private String province;
private String city;
private String street;
private String zipcode;
// 构造方法
public Address() {}
public Address(String country, String province, String city, String street, String zipcode) {
this.country = country;
this.province = province;
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// 信息打印
public String getInfo() {
return "国家:"+this.country+"、省份:"+this.province+"、城市:"+this.city+"、街道:"+this.street+"、邮编:"+this.zipcode;
}
// set函数
public void setCountry(String country) {
this.country = country;
}
public void setProvince(String province) {
this.province = province;
}
public void setCity(String city) {
this.city = city;
}
public void setStreet(String street) {
this.street = street;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
// get函数
public String getCountry() {
return this.country;
}
public String getProvince() {
return this.province;
}
public String getCity() {
return this.city;
}
public String getStreet() {
return this.street;
}
public String getZipcode() {
return this.zipcode;
}
}
public class JavaDemo {
public static void main(String args[]) {
System.out.println(new Address("中华人民共和国","北京","北京","天安门街道","10001").getInfo());
}
}
package Java_Learn;
class Employee{
private long empno;
private String ename;
private double salary;
private double rate;
// 构造方法
public Employee() {}
public Employee(long empno, String ename, double salary, double rate) {
this.empno = empno;
this.ename = ename;
this.salary = salary;
this.rate = rate;
}
// 获取信息
public String getInfo() {
return "雇员编号:"+this.empno+"、雇员姓名:"+this.ename+"、基本工资:"+this.salary+"、工资增长率:"+this.rate;
}
// 得到薪水的增长额度
public double salaryIncValue() {
return this.salary * this.rate;
}
// 得到薪水增长总额
public double salaryIncResult() {
this.salary = this.salary * (1 + this.rate);
return this.salary;
}
}
public class JavaDemo {
public static void main(String args[]) {
Employee emp = new Employee(6527L,"史密斯",3000.0,0.25);
System.out.println(emp.getInfo());
System.out.println("工资调整额度:"+emp.salaryIncValue());
System.out.println("工资调整结果:"+emp.salaryIncResult());
System.out.println(emp.getInfo());
}
}
package Java_Learn;
class Dog {
private String name;
private String color;
private int age;
// 构造函数
public Dog() {}
public Dog(String name,String color,int age) {
this.name = name;
this.color = color;
this.age = age;
}
// 获取信息
public String getInfo() {
return "狗的名字:"+this.name+"、颜色:"+this.color+"、年龄:"+this.age;
}
}
public class JavaDemo {
public static void main(String args[]) {
Dog dog = new Dog("高高","黄色",5);
System.out.println(dog.getInfo());
}
}
package Java_Learn;
class Account {
private String name;
private double balance;
// 构造函数
public Account() {}
public Account(String name) {
this(name, 0.0); // 调用双参构造,银行开户
}
public Account(String name, double balance) {
this.name = name;
this.balance = balance;
}
// 得到总额
public double getBalance() {
return this.balance;
}
// 得到信息
public String getInfo() {
return "账户名称:"+this.name+"、账户余额:"+this.balance;
}
}
public class JavaDemo {
public static void main(String args[]) {
Account account = new Account("demo", 900000.0);
System.out.println(account.getInfo());
System.out.println(account.getBalance());
}
}
package Java_Learn;
class User {
private String uid;
private String password;
private static int count = 0;
public User() {
this("NOID","java");
}
public User(String uid) {
this(uid,"java");
}
public User(String uid, String password) {
this.uid = uid;
this.password = password;
this.count ++;
}
public String getInfo() {
return "用户名:"+this.uid+"、密码:"+this.password;
}
public static int getCount() {
return count;
}
}
public class JavaDemo {
public static void main(String args[]) {
User userA = new User();
User userB = new User("小强");
User userC = new User("大强", "我不行");
System.out.println(userA.getInfo());
System.out.println(userB.getInfo());
System.out.println(userC.getInfo());
System.out.println("用户个数:"+User.getCount());
}
}
package Java_Learn;
class Book {
private String title;
private int bid;
private double price;
private static int count = 0;
public Book(String title, double price) {
this.bid = count + 1;
this.title = title;
this.price = price;
count ++;
}
public String getInfo() {
return "图书名称:"+this.title+"、图书编号:"+this.bid+"、图书价格:"+this.price;
}
public static int getCount() {
return count;
}
}
public class JavaDemo {
public static void main(String args[]) {
Book b1 = new Book("Java", 89.2);
Book b2 = new Book("Oracal",79.2);
System.out.println(b1.getInfo());
System.out.println(b2.getInfo());
System.out.println("图书总册数:"+Book.getCount());
}
}
数组
数组的基本概念:
- 一组相关变量的集合
- 引用数据类型
- 关键字new
- 内存分配
- 动态初始化:数据类型[] 数组名称 = new 数据类型[长度]
- 静态初始化:数据类型[] 数组名称 = new 数据类型[]{数据1, 数据2, 数据3, …}
- 数组脚标:0 ~ (数组长度-1)
- 数组的长度:数组名称.length
数组的引用传递:一个堆内存可以被多个栈内存指向
foreach迭代:自动获取数组中的每一个元素,避免数组的下标越界
for(数据类型 变量: 数组名称){}
二维数组:
- 动态初始化:数据类型【】【】 数组名称 = new 数据类型【行个数】【列个数】
- 静态初始化:数据类型【】【】 数组名称 = new 数据类型【】【】{{数据1,数据2,、、、},{数据1,数据2,、、、},、、、}
- 每一行为一个一维数组
数组与方法:数组的传递与接收,同一块堆内存被不同的栈内存指向
数组排序:类的静态方法(类名.静态方法())调用
数组转置:反转操作,首尾交换
- 定义一个新的数组,将之前的数据逆序存放;
- 在初始数组中两两交换;
数组类库:
- 排序函数:java.util.Arrays.sort()
- 数组拷贝:System.arraycopy(源数组,源数组开始点,目标数组,目标数组开始点,拷贝长度)
方法可变参数: public static int sum(int … data),传入多个参数,data为变种数组
对象数组:
- 动态初始化:类[] 对象数组名称 = new 类[长度],每一个元素的内容都是null
- 静态初始化:类[] 对象数组名称 = new 类[] {实例化对象,…}
引用传递(引用数据类型的关联)
类关联结构:不同类的实例对象之间
- 设置对象之间的关系
- 根据关系获取数据
自身关联:同一个类的不同实例对象之间
合成设计模式:一个类由其他多个类组成,可以拆分,而后重新组合
数据表与简单Java类的映射转换
基本映射关系:
- 数据实体表设计 = 类的定义
- 表中的字段 = 类的成员属性
- 表的外键关联 = 引用关联
- 表的一行记录 = 类的一个实例化对象
- 表的多行记录 = 类的对象数组
映射转换的步骤:
- 根据表的结构关系进行对象的配置
- 根据要求通过结构获取数据
一对多映射:
- 获取一个分类的完整信息
- 根据分类获取其对应的所有子类的信息
多对多映射:只需要考虑实体表的设计
复杂多对多映射: 权限问题
String类特点分析
不是基本数据类型,每一个字符保存在(char JDK1.9之前,之后是byte )数组类型中
-
直接赋值:String str = “demo”
-
构造方法实例化:String str = new String(“demo”)
字符串比较:public boolean equals(String str)
String类的匿名对象,一定是开辟好堆内存空间的
直接赋值的对象实例化模式:可以实现同一个字符串对象的共享操作,字符串对象池,自动将对象保存到对象池中
构造方法实例化模式:开辟属于自己专用的内存空间,.intern()函数将构造方法的对象加入对象池中
String对象池(常量池):
- 静态常量池:程序加载时,会自动将此程序中保存的字符串或者普通常量等等全部进行分配
- 运行时常量池:当一个程序加载后,里面可能的变量使用的常量池
字符串内容不可修改:修改String变量会产生新的内存空间,同时产生垃圾空间
主方法
public :描述的是一种访问权限,主方法是一切的开始点,开始点一点是公共的
static :程序的执行是通过类名称完成的,表示此方法是由类直接调用
void :主方法是一切的起点,起点一旦开始就没有返回的可能
main :是一个系统定义好的方法名称
String args[] :字符串的数组,可以实现程序启动参数的接收
String类常用方法
Java的API文档 => JavaDoc
字符串与字符数组:
构造方法与普通方法
toCharArray() => 将字符串转为字符数组
使用char类型的数据,由于其包含中文字符
字符串与字节数组:
进行二进制的数据传输或者进行编码转换
getBytes() => 字符串转字节数组
字符串比较:
equals()
equlasIngnoreCase()
compareTo() 进行字符串大小比较,返回ASCII码的差值(前一个与后一个)
字符串查找:
contains() 判断此字符串是否存在
indexof() 查找指定字符串的位置
字符串替换:
replaceAll() 进行全部替换
字符串拆分:
split() 根据条件拆分
拆不开使用 ‘\’ 转义
字符串截取:
substring() 从指定位置到末尾
字符串格式化:
format() 根据指定结构进行文本格式
其他:
concat() 字符串拼接
isEmpty() 判断是否为空字符串,字符串已经实例化,而不是null
length() 返回字符串长度
trim() 去除字符串前后的空格
toUpperCase() 字符串转大写
toLowerCase() 字符串转小写
继承的定义与使用
可以扩充已有类的功能
extends关键字 => class 子类 extends 父类 {}
子类 => 派生类
父类 => 超类
super()表示子类构造调用父类构造,只允许放在子类构造方法的首行。
super()调用父类,this()调用子类,两个不能同时出现。
不允许多重继承,只允许多层继承。
方法的覆写
子类定义了与父类方法名称相同,参数类型及个数完全相同
要在子类中使用被覆写的父类方法,使用super.父类方法()
访问控制权限:public > default > private
default(父类)=> public / default(子类)
public (父类) => public(子类)
Overloading 重载
=> 参数类型及个数不同
=> 发生在一个类中
=> 没有权限限制
Override 覆写
=> 子类不能拥有比父类更严格的控制权限
=> 发生在继承类中
属性覆盖
super与this
final关键字:定义不能被继承的类,定义不能被继承的属性和方法
使用final关键字定义常量
全局常量:public static final int 常量名 = 常量值;
案例分析
// 学生类
class Person {
private String name;
private String addr;
private char sex;
private int age;
public Person() {}
public Person(String name,String addr) {
this(name,addr,'男',0);
}
public Person(String name,String addr,char sex,int age) {
this.name = name;
this.addr = addr;
this.sex = sex;
this.age = age;
}
public String getInfo() {
return "名字:" + this.name + "、地址:"+this.addr
+ "、性别:" +this.sex+"、年龄:"+this.age;
}
}
class Student extends Person{
private double math;
private double english;
public Student() {}
public Student(String name,String addr) {
super(name,addr);
}
public Student(String name,String addr,char sex,int age,double math,double english) {
super(name,addr,sex,age);
this.math = math;
this.english = english;
}
public String getInfo() {
return super.getInfo()+"、数学成绩:"+this.math+"、英语成绩:"+this.english;
}
}
public class Main {
public static void main(String[] args) {
Student stu = new Student("张三","天安门",'男',12,78.99,89.98);
System.out.println(stu.getInfo());
}
}
// 管理人员与职员类
class Employee {
private String name;
private int age;
private String sex;
public Employee() {}
public Employee(String name,int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getInfo() {
return "姓名:"+this.name+"、年龄:"+this.age+"、性别:"+this.sex;
}
}
class Manager extends Employee {
private String job;
private double income;
public Manager() {}
public Manager(String name,int age,String sex,String job,double income) {
super(name,age,sex);
this.job = job;
this.income = income;
}
public String getInfo() {
return "【管理层】" + super.getInfo()+"、职务:"+this.job+"、年薪:"+this.income;
}
}
class Staff extends Employee {
private String dept;
private double salary;
public Staff() {}
public Staff(String name,int age,String sex,String dept,double salary) {
super(name,age,sex);
this.dept = dept;
this.salary = salary;
}
public String getInfo() {
return "【职员】"+super.getInfo()+"、部门:"+this.dept+"、月薪:"+this.salary;
}
}
public class Main {
public static void main(String[] args) {
Manager man = new Manager("张三",38,"女","主管",150000.00);
Staff sta = new Staff("李四",18,"男","出纳",3000.00);
System.out.println(man.getInfo());
System.out.println(sta.getInfo());
}
}
// 字符串统计类
class StringUtil {
private String content;
public StringUtil(String content) {
this.content = content;
}
public String getContent() {
return this.content;
}
public String getInfo() {
return this.getContent();
}
}
class StringCount extends StringUtil {
private int nCount;
private int oCount;
public StringCount(String content) {
super(content);
}
public void count() {
char[] data = super.getContent().toCharArray();
for(int x=0;x<data.length;x++) {
if(data[x]=='n'||data[x]=='N') {
this.nCount++;
}
if(data[x]=='o'||data[x]=='O') {
this.oCount++;
}
}
}
public int getNCount() {
return this.nCount;
}
public int getOCount() {
return this.oCount;
}
public String getInfo() {
return "字母n的个数:"+this.getNCount()+"、字母o的个数:"+this.getOCount();
}
}
public class Main {
public static void main(String[] args) {
String str = "wangt you to know one thing";
StringCount c = new StringCount(str);
c.count();
System.out.println(c.getInfo());
}
}
// 数组操作类
class Array {
private int[] data;
private int foot;
public Array(int len) {
if(len > 0) {
this.data = new int[len];
} else {
this.data = new int[1];
}
}
public void increment(int num) {
int[] newData = new int[this.data.length+num];
System.arraycopy(this.data, 0, newData, 0, this.data.length);
this.data = newData;
}
public boolean add(int num) {
if(this.foot < this.data.length) {
this.data[this.foot++] = num;
return true;
}
return false;
}
public int[] getData() {
return this.data;
}
}
class SortArray extends Array {
public SortArray(int len) {
super(len);
}
public int[] getData() {
java.util.Arrays.sort(super.getData());
return super.getData();
}
}
class ReverseArray extends Array {
public ReverseArray(int len) {
super(len);
}
public int[] getData() {
int center = super.getData().length / 2;
int head = 0;
int tail = super.getData().length-1;
for(int x=0;x<center;x++) {
int temp = super.getData()[head];
super.getData()[head] = super.getData()[tail];
super.getData()[tail] = temp;
head++;
tail--;
}
return super.getData();
}
}
public class Main {
public static void main(String[] args) {
ReverseArray arr = new ReverseArray(5);
System.out.println(arr.add(10));
System.out.println(arr.add(5));
System.out.println(arr.add(20));
System.out.println(arr.add(3));
System.out.println(arr.add(6));
arr.increment(3);
System.out.println(arr.add(1));
System.out.println(arr.add(7));
System.out.println(arr.add(0));
int[] result = arr.getData();
for(int temp: result) {
System.out.print(temp+"、");
}
}
}
Annotation注解
以注解的形式实现的程序开发
程序开发过程一:在程序定义的时候将所有可能使用到的资源全部定义在程序代码之中
程序开发过程二:引入配置文件,在配置文件中定义要全部使用的服务器资源
程序开发过程三:将配置文件的信息重新写回到程序之中,利用一些特殊的标记与程序代码进行分离
准确覆写 :@Override
过期声明(操作) :@Deprecated
压制警告 :@SuppressWarnings
多态性
在继承性的基础上扩展的,可以实现实现父子类之间的互相转换处理
多态性的概念
- 方法的多态性
- 方法的重载
- 方法的覆写
- 对象的多态性:父子实例之间的转换处理
- 对象的向上转型:
- 父类 父类实例 = 子类实例
- 自动完成转换
- 主要特点在于可以对参数进行统一的设计
- 可维护性设计
- 对象的向下转型:
- 子类 子类实例 = (子类)父类实例
- 强制完成转换
- 主要特点在于需要使用一些子类自己特殊的定义处理
- 在进行向下转型前必须要先进行向上转型
- 对象的向上转型:
instanceof关键字
语法:对象 instanceof 类
返回一个boolean类型的结果,true表示实例是指定类对象
执行向下转型前,先进行instanceof判断
object类
主要特点:解决参数的统一问题
使用object类可以接收所有的数据类型
唯一一个不存在继承关系的类, 即所有类都是object的子类
获取一个对象的全部信息:toString()(覆写此方法)
对象比较:equals()(覆写此方法)
对象内容比较 与 对象地址比较
抽象类的定义与使用
父类对子类进行强制性约定,必须对方法进行覆写
抽象类主要作用:对子类中的覆写方法进行约定
关键字:abstract
没有提供方法体的方法,抽象方法所在的类必须是抽象类
抽象类不是完整的类
- 抽象类必须提供有子类,子类使用extends继承一个抽象类;
- 抽象类的子类一定要覆写抽象类中的全部抽象方法;
- 抽象类的对象实例化可以利用对象多态性通过子类向上转型的方式完成;
抽象类比普通类增加了抽象方法以及对子类的强制性覆写要求
几点意见:
- 抽象类自己无法直接实例化
- 抽象类的主要目的是进行过渡操作使用,类继承问题所带来的的代码重复
注意:
- 在定义抽象类的时候绝对不能使用final关键字来定义
- 抽象类是作为一个普通类的加强版出现的
- 抽象类中允许没有抽象方法,但是仍无法使用new关键字实例化抽象类
- 抽象类中可以提供有static方法,并且该方法不受到抽象类对象的局限
对子类方法的统一管理
可以自身提供一些普通方法调用抽象方法,抽象方法只有在子类实例化中才会生效
包装类
主要功能:针对于基本数据类型的对象转换而实现的,
装箱:将基本数据类型包装为一个类,即保存在包装类中
拆箱:从包装类对象中获取基本数据类型
两种类型的包装类:
- 对象型的包装类:Object直接子类,Boolean、Character
- 数值型的包装类:Number(抽象类)直接子类,Byte、Short、Integer、Long、Float、Double
数据装箱 与 数据拆箱
Object obj = 19.2; // 自动将double转型为Double类,即数据装箱
double num = (Double)obj; // 强制将Object类转为Double类,再自动进行数据拆箱
接口的定义与使用
接口是一个纯粹的抽象类,包含有抽象方法、全局变量、普通方法和静态方法
关键字:interface
接口名称前加入字母I(inteface)区分抽象类与接口
接口无法直接产生实例化对象,使用原则如下:
- 接口需要被子类实现(implements),一个子类可以实现多个父接口;
- 子类一定要覆写接口中的全部抽象方法;
- 接口对象可以利用子类对象的向上转型进行实例化;
object类可以接收接口,接口描述的是一个公共的定义标准,接口之中所有抽象方法的访问权限都是public
接口中可以省略abstract,但是抽象类中不允许省略。
接口多继承
extends只能继承一个父类,但是可以继承多个父接口。
接口使用的三种形式:
- 进行标准设置
- 表示一种操作的能力
- 暴露远程方法视图,一般都在RPC分布式开发中使用
接口定义加强
当接口的子类过多的情况,同时需要增加一些方法,可以使用过渡抽象类
接口中的普通方法定义必须追加default声明,该操作是补充操作,不应该作为程序设计的首选
接口定义标准
工厂设计模式:Factory
代理设计模式:Proxy
帮助用户将所有开发注意力集中在核心业务功能上
一个接口提供有两个子类,一个子类是真实业务操作类,另一个子类是代理业务操作类。
抽象类与接口的区别:
- 定义关键字
- 组成
- 权限
- 子类使用
- 两者关系:
- 抽象类可以实现若干个接口
- 接口不允许继承抽象类,但可以继承多个父接口父接口
- 使用:
- 抽象类或接口必须定义子类
- 子类一定要覆写抽象类或接口中的全部抽象方法
- 通过子类的向上转型实现抽象类或接口对象实例化
当抽象类和接口都可以使用的时候优先考虑接口,因为接口可以避免子类单继承的局限
案例分析
// 获取类信息
interface IClassName {
public String getClassName() ;
}
class Company implements IClassName {
public String getClassName() {
return "Company";
}
}
public class Main {
public static void main(String[] args) {
IClassName ica = new Company();
System.out.println(ica.getClassName());
}
}
// 绘图处理
interface IGraphical {
public void paint() ;
}
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
}
class Triangle implements IGraphical {
private Point[] x;
private Point[] y;
private Point[] z;
public Triangle(Point[] x, Point[] y, Point[] z) {
this.x = x;
this.y = y;
this.z = z;
}
public void paint() {
System.out.println("绘制第一条边,开始坐标:["+this.x[0].getX() + ", " + this.x[0].getY()
+ "], 结束坐标:["+this.x[1].getX() + ", " + this.x[1].getY() + "]");
System.out.println("绘制第二条边,开始坐标:["+this.y[0].getX() + ", " + this.y[0].getY()
+ "], 结束坐标:["+this.y[1].getX() + ", " + this.y[1].getY() + "]");
System.out.println("绘制第一条边,开始坐标:["+this.z[0].getX() + ", " + this.z[0].getY()
+ "], 结束坐标:["+this.z[1].getX() + ", " + this.z[1].getY() + "]");
}
}
class Circular implements IGraphical{
private double radius ;
public Circular(double radius) {
this.radius = radius;
}
public void paint() {
System.out.println("以半径" + this.radius +"绘制图形。");
}
}
class Factory {
public static IGraphical getInstance(String className, double ... args) {
if("triangle".equalsIgnoreCase(className)) {
return new Triangle(
new Point[] {new Point(args[0],args[1]),new Point(args[2],args[3])},
new Point[] {new Point(args[4],args[5]),new Point(args[6],args[7])},
new Point[] {new Point(args[8],args[9]),new Point(args[10],args[11])});
} else if ("circular".equalsIgnoreCase(className)) {
return new Circular(args[0]);
} else {
return null;
}
}
}
public class Main {
public static void main(String[] args) {
IGraphical iga = Factory.getInstance("triangle", 1.1,2.2,3.3,4.4,11.11,22.22,33.33,44.44,111.111,222.222,333.333,444.444);
iga.paint();
IGraphical igb = Factory.getInstance("circular", 88.11);
igb.paint();
}
}
// 图形
abstract class AbstractShape {
public abstract double area() ;
public abstract double perimeter() ;
}
class Circular extends AbstractShape {
private double radius;
public Circular(double radius) {
this.radius = radius;
}
public double area() {
return Math.PI * this.radius * this.radius;
}
public double perimeter() {
return Math.PI * this.radius * 2;
}
}
class Rectangle extends AbstractShape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
public double area() {
return this.length * this.width;
}
public double perimeter() {
return 2 * (this.length + this.width);
}
}
class Factory {
public static AbstractShape getInstance(String className, double ... args) {
if("Circular".equalsIgnoreCase(className)) {
return new Circular(args[0]);
} else if ("Rectangle".equalsIgnoreCase(className)) {
return new Rectangle(args[0],args[1]);
} else {
return null;
}
}
}
public class Main {
public static void main(String[] args) {
AbstractShape asa = Factory.getInstance("Circular", 1.1);
AbstractShape asb = Factory.getInstance("Rectangle", 1.5,10.2);
System.out.println("圆形面积:"+asa.area()+"、圆形周长:"+asa.perimeter());
System.out.println("矩形面积:"+asb.area()+"、矩形周长:"+asb.perimeter());
}
}
泛型
主要目的:为了解决ClassCastException问题
转型关系:
- 整型数据:基本数据类型 -> 包装为Integer类对象 -> 自动向上转型为Object
- 浮点型数据:基本数据类型 -> 包装为Double类对象 -> 自动向上转型为Object
- 字符串型数据:String类对象 -> 自动向上转型为Object
Object结束范围太广,会产生极大的安全隐患。
避免ClassCastException最好的做法是直接回避对象的强制转换
泛型的本质:类中的属性或方法的参数与返回值的类型可以由对象实例化的时候动态确定
class point <T> {}
point<Integer> demo = new point<Integer>();
泛型定义使用时,如果没有设置T的类型,将自动使用Object进行处理。
注意:
- 泛型之中只允许设置引用类型,如果现在要操作基本类型必须使用包装类
- 泛型实例化可简写为“point demo = new point();”
泛型通配符
泛型增加了引用传递问题
使用通配符“?”,解决泛型的问题。
参数:point <?> temp
小的通配符:
- ? extends 类名:设置泛型的上限
- ? super 类名:设置泛型的下限
泛型接口
interface IMessage() {}
- 在子类之中继续使用泛型定义
- 在子类实现父接口的时候直接定义出具体数据类型
泛型方法
具有泛型标记的参数的方法,但泛型方法不一定出现在泛型类之中
public static T[] fun(T … args) {}
包的定义与使用
利用包实现类的包装
同一个目录下不允许存在相同名称的程序类文件
import导入其他包中的程序类
javac -d . *.java 编译
关于public class与class定义的区别:
- public class:类名称必须与文件名称保持一致,一个*.java文件里面只允许有一个public class,如果一个类要允许被其他包使用,那么这个类一定要定义为public class
- class:类名称可以与文件名称不一致,“*.java”文件里面可以提供有多个class定义,编译后将形成“ *.class”的文件,但是这些类只能被本包的类使用,外包无法访问。
- 在实际的开发之中往往在一个*.java源代码文件里面只会提供有一个程序类,而这个程序类一般都使用class。程序类中定义的包名称必须采用小写字母的形式定义。
通配符“*”导入包中的所有类
出现重复的类名称,使用完整的 包名+类名
包的静态导入 => 包.类中的静态方法
import static 包名.类名.*
生成jar包
jar命令 => jar --help
- 编译处理:javac -d . Message.java
- 编译完成后会生成cn文件,其中有对应的子包和*.class文件,将其打包为mldn.jar,jar -cvf mldn.jar cn
- -c 创建一个新的jar文件
- -v 得到一个详细输出
- -f 设置要生成的jar文件名称
- 解释程序:java 包名.类名
SET CLASSPATH=.;jar路径 => 设置jar路径,便于使用
系统常用包
java.lang : String类,Number类在其中
java.util :实现工具类的定义,包括数据结构的定义
java.io :输入与输出流操作的程序包
java.sql :进行数据库编程的开发包
java.net : 网络程序开发的程序包
java.applet : 直接嵌套在网页上执行的程序
java.awt / javax.swing :图形界面开发包,awt是重量级的开发包,swing是轻量级的开发包
访问权限控制 => 封装性
访问范围 | private | default | protected | public |
---|---|---|---|---|
同一包中的同一类 | √ | √ | √ | √ |
同一包中的不同类 | × | √ | √ | √ |
不同包的子类 | × | × | √ | √ |
不同包的所有类 | × | × | × | √ |
UML图形
统一的建模语言,本质是利用图形化的形式来实现程序类关系的描述。
类图:
类名称(抽象类类名称为斜体) |
---|
属性(访问权限 属性名称 : 属性类型) |
方法(访问权限 方法名称() : 返回值) |
访问权限描述:public(+),private(-),protected(#)
时序图
描述的是代码的执行流程
用例图
描述的是程序的执行分配
单例设计模式
只允许提供有一个实例化对象
使用static方法实例化对象,保证只有一个实例化对象,使用关键字final
多例设计
实例化对象的数量较多,且在同一个对象中实例化
枚举
用于定义有限个数对象的一种结构(多例设计)
枚举属于多例设计模式,但结构比多例设计模式更简单
基本定义:关键字enum实现枚举定义
枚举可以判断实例化对象是否存在,而多例设计无法判断
Enum类:java.lang.Enum
枚举对象写在第一行,使用private定义构造方法
主要作用:定义实例对象的范围
异常的捕获与处理
异常:指的是导致程序中断执行的一种指令流
try {
可能出现异常的语句
} catch (异常类型 异常对象) {
异常处理
} finally {
不管异常是否处理都要执行
}
异常处理流程:
1、在程序运行过程中才会产生异常,而一旦程序执行中产生了异常之后将自动进行指定类型的异常类对象实例化;
2、如果此时程序并没有提供异常的处理支持,则会采用JVM默认异常处理方式,首先进行异常信息的打印,而后直接退出当前的程序;
3、此时程序中如果存在有异常处理,那么这个产生的异常类的实例化对象将会被try语句所捕获;
4、try捕获异常之后与其匹配的catch中的异常类型进行依次比对,如果此时与catch中的异常类匹配完成,则用此catch进行异常处理。如果并没有任何的catch匹配成功,则该异常未处理成功;
5、不管异常是否处理最终都要执行finally语句,当执行完成finally的程序会进一步判断当前的异常是否已经处理。处理过则继续向后执行代码,如果未处理则交由JVM进行默认处理;
throws关键字 => 自动进行异常的默认抛出处理
throw关键字 => 手动进行抛出异常的处理
RuntimeException 与 Exception
自定义异常类 =>
- 继承Exception
- 继承RuntimeException
assert断言
内部类
一个独立且完善的类结构
内部类本身最大的缺陷在于破坏了程序的结构
内部类可以轻松访问外部类的私有属性和私有方法,同理外部类亦可。
外部类.内部类 内部类对象= new 外部类().new 内部类();
可以对内部类进行private私有化
使用static定义内部类,则内部类变为了外部类
类方法中定义内部类(JDK1.8以前属性要加final)
匿名内部类
函数式编程
Lambda表达式
实现要求:SAM (Single Abstract Method)
函数式接口:方法只能有一个
格式:
- 方法没有参数:() -> {};
- 方法有参数:(参数, 参数) -> {};
- 只有一行语句:(参数, 参数) -> 语句;
方法的引用
- 引用静态方法:类名称 :: static 方法名称 ;
- 引用某个实例对象的方法:实例化对象 :: 普通方法 ;
- 引用特定类型的方法:特定类 :: 普通方法 ;
- 引用构造方法:类名称 :: new ;
利用方法引用可以为一个方法定义多个名字,但是要求必须是函数式接口。
@FunctionalInterface => 注解声明
内建函数式接口(java.util.function):
- 功能性函数式接口;
- 消费型函数式接口:只能进行数据的处理操作,而没有任何的返回;
- 供给型函数式接口;
- 断言型函数式接口;进行判断处理
链表
一个动态的对象数组,可以实现若干个对象的存储。
利用引用的逻辑关系来实现类似于数组的数据处理操作。
package first;
interface ILink<E> { // 设置泛型,避免安全隐患
public void add(E e); // 增加数据
public int size(); // 获取数据的个数
public boolean isEmpty(); // 空集合判断
public Object[] toArray(); // 返回集合数据
public E get(int index); // 获取指定索引数据
public void set(int index, E data); // 修改指定索引的数据
public boolean contains(E data); // 判断指定数据是否存在
public void remove(E data); // 数据删除
public void clean(); // 清空链表
}
class LinkImpl<E> implements ILink<E> {
private class Node { // 保存节点的数据关系
private E data; // 保存数据
private Node next; // 保存下一个引用
public Node (E data) { // 有数据的情况下才有意义
this.data = data;
}
public void addNode(Node newNode) {// 保存新的Node数据
if(this.next == null) {// 当前节点的下一个节点为null
this.next = newNode; // 保存当前节点
} else {
this.next.addNode(newNode);
}
}
public void toArrayNode() {
LinkImpl.this.returnData[LinkImpl.this.foot++] = this.data;
if(this.next != null) {// 还有下一个数据
this.next.toArrayNode();
}
}
public E getNode(int index) {
if(LinkImpl.this.foot++ == index) {// 索引相同
return this.data; // 返回当前数据
} else {
return this.next.getNode(index);
}
}
public void setNode(int index, E data) {
if(LinkImpl.this.foot++ == index) {// 索引相同
this.data=data; // 返回当前数据
} else {
this.next.setNode(index, data);
}
}
public boolean containsNode(E data) {
if(data.equals(this.data)) { // 对象比较
return true;
} else {
if(this.next == null) { // 没有后续节点
return false; // 找不到
} else {
return this.next.containsNode(data); // 向后继续判断
}
}
}
public void removeNode(Node previous, E data) {
if(this.data.equals(data)) {
previous.next = this.next; // 空出当前节点
} else {
if(this.next != null) {// 有后续节点
this.next.removeNode(this, data);// 向后继续删除
}
}
}
}
// ---------------- 以下为Link类中定义的成员 --------------------
private Node root; // 保存根元素
private int count; // 保存数据个数
private int foot; // 描述的是操作数组的脚标
private Object[] returnData; // 返回的数据保存
// ---------------- 以下为Link类中定义的方法 --------------------
public void add(E e) {
if(e == null) { // 保存的数据为null
return;
}
// 数据本身是不具有关联性的,只有Node类有
Node newNode = new Node(e); // 创建一个新的节点
if(this.root == null) { // 现在没有根节点
this.root = newNode; // 第一个节点作为根节点
} else { // 根节点存在
this.root.addNode(newNode); // 将根节点保存在合适的位置
}
this.count++;
}
public int size() {
return this.count;
}
public boolean isEmpty() {
// return this.root== null;
return count == 0;
}
public Object[] toArray() {
if(this.isEmpty()) {// 空集合
return null; // 现在没有数据
}
this.foot = 0; // 脚标清零
this.returnData = new Object[this.count]; // 根据已有长度定义
this.root.toArrayNode(); // 利用脚标递归传入数据
return returnData;
}
public E get(int index) {
if(index >= this.count) {// 索引应该在指定的范围之内
return null;
} // 索引数据的获取应该由Node类来完成
this.foot = 0; // 重置索引的下标
return this.root.getNode(index);
}
public void set(int index, E data) {
if(index >= this.count) {// 索引应该在指定的范围之内
return ; // 方法结束
} // 索引数据的获取应该由Node类来完成
this.foot = 0; // 重置索引的下标
this.root.setNode(index, data); // 修改数据
}
public boolean contains(E data) {
if(data == null) {
return false; // 没有数据
}
return this.root.containsNode(data); // 交给Node类判断
}
public void remove(E data) {
if(this.contains(data)) {// 判断数据是否存在
if(this.root.data.equals(data)) {// 根节点为要删除的节点
this.root = this.root.next; // 根的下一个节点
} else { // 交由Node负责
this.root.next.removeNode(this.root, data);
}
this.count--;
}
}
public void clean() {
this.root = null; // 后续所有节点都没了
this.count = 0; // 个数清零
}
}
public class Main {
public static void main(String[] args) {
ILink<String> all = new LinkImpl<String>();
System.out.println("【增加之前】数据个数:"+all.size() + "、"+all.isEmpty());
all.add("Hello");
all.add("World");
all.add("MLDN");
all.remove("World");
System.out.println("【增加之后】数据个数:"+all.size()+"、"+all.isEmpty());
Object result[] = all.toArray();
for(Object obj : result) {
System.out.println(obj);
}
System.out.println("----------------数据获取-----------------");
System.out.println(all.get(0));
System.out.println(all.get(1));
System.out.println(all.get(4));
System.out.println("--------------数据判断-------------------");
System.out.println(all.contains("搞"));
System.out.println(all.contains("Hello"));
}
}