目录
01 面向过程与面向对象
面向过程(Procedure Oriented Programming)
面向对象是相对于面向过程而言的。面向过程, 强调的是 功能 行为,以函数为最小单位,考虑怎么做
面向对象(Object Oriented Programming)
面向对象,将功能封装进对象, 强调具备了功能 的 对象,以类 对象为最小单位,考虑谁来做。
面向对象内容的三条主线
- Java 类及类的成员:
- 属性、方法、构造器、代码块、内部类 *
- 面向对象的三大特征:
- 封装、继承、多态性、(抽象性) *
- 其它关键字:
- this、super、static、final、abstract、interface、package、import 等
- this、super、static、final、abstract、interface、package、import 等
面向对象思想概述
- 程序员从面向过程的执行者转化成了面向对象的指挥者
- 面向对象分析方法分析问题的思路和步骤:
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
- (名词可以定义为类,动词是需要类所具有的功能)
02 类与对象
面向对象的两个要素
- 类:对一类事物的描述,是抽象的、概念上的定义
- 对象:是实际存在的该类事物的每个个体,因而也称为实 例(instance)。
可以理解为:类= 抽象概念的人;对象= 实实在在的某个人
面向对象程序设计的重点是类的设计;
设计类,其实就是设计类的成员。
2.1 Java 类及类的成员
Java 中常见的类的成员有:
- 属性:对应类中的成员变量
- 行为:对应类中的成员方法
举例一
举例二
2.2 对象的创建与使用
类的语法格式
public class Person{
private int age; // 声明私有变量age
public void showAge(int i){ //声明方法 showAge
age = i;
}
}
创建一个自定义类
public class PersonTest {
public static void main(String[] args) {
// 2. 在主程序中新建一个类的实例
// 类名对象名= new 类名();
Person Zhangsan = new Person();
// 调用类的结构:属性和方法
Zhangsan.name = "Zhangsan";
Zhangsan.age = 17;
Zhangsan.isMale = true;
System.out.println(Zhangsan.name); // Zhangsan
System.out.println(Zhangsan.age); // 17
// 调用方法
Zhangsan.eat();
Zhangsan.sleep();
Zhangsan.talk();
//****************
Person P2 = new Person();
//不定义初始值
System.out.println(P2.name); //null
System.out.println(P2.isMale); // false
//**************
Person p3 = Zhangsan; //将 p1 变量保存的对象地址值赋给 p3,导致 p1 和 p3 指向了堆空间中的一个对象实体。
System.out.println(p3.name); // Zahngsan
p3.age = 10;
System.out.println(p3.age); //10
}
}
/*
1. 声明一个类
修饰符 class 类名{
属性声明;
方法声明;
}
说明:修饰符 public:类可以被任意访问类的正文要用{ }括起来
*/
class Person{
// 类的属性
String name;
int age;
boolean isMale;
// 定义方法
public void eat(){
System.out.println("eating");
}
public void sleep(){
System.out.println("Sleeping");
}
public void talk(){
System.out.println("talking");
}
}
文字说明
- 创建对象语法: 类名 对象名 = new 类名
- 使用“ 对象名.对象成员 ”的方式访问对象成员(包括属性和 方法)
- 如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰。(Zhangsan 和Lisi 是两个人)
类的访问机制:
- 在一个类中的访问机制: 类中的方法可以直接访问类中的成员变量 。
- 例外: static 方法访问非 static 编译不通过 。(static方法和类同时加载,非静态方法需要创建一个对象后才加载)
- 在不同类中的访问机制: 先创建要访问类的对象 再用对象访问类中定义的成员 。
2.3 对象的创建和使用:内存解析
- 堆(Heap)
- 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
- 栈(Stack)
- 是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放。
- 方法区(MethodArea)
- 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
举例
p1 = new Person
p1.name = "Tom";
p1.isMale = true
Person p2 = new Person
sysout(p2.name);//null
Person p3 = p1
p3.age = 10;
03 类的成员之一:属性(filed)
语法格式
变量分类
- 在方法体外,类体内声明的变量称为成员变量(属性)。
- 在方法体内部声明的变量称为局部变量。
属性和局部变量的异同点
- 相同点:
- 定义变量的格式:数据类型 变量名 = 变量值
- 先声明,后使用
- 变量都有其对应的作用域
- 不同点:
- 在类中声明的位置不同
- 属性:直接定义在类的一对{}内
- 局部变量:声明在方法内、方法形参、构造器形参、构造器内部的变量
- 关于权限修饰符的不同
- 属性:可以在声明属性时,指明其权限,使用权限修饰符。
- 常用的权限修饰符:private、public、缺省、protected
- 目前声明属性时,都使用缺省即可。
- 局部变量:不可以使用权限修饰符。
- 属性:可以在声明属性时,指明其权限,使用权限修饰符。
- 默认初始化值的情况:
- 属性:类的属性,根据其类型,都有默认初始化值。
- 整型(byte、short、int、long):0
- 浮点型(float、double):0.0
- 字符型(char):0(或‘\u0000’)
- 布尔型(boolean):false
- 引用数据类型(类、数组、接口):null
- 属性:类的属性,根据其类型,都有默认初始化值。
- 局部变量:没有默认初始化值
- 意味着:在调用局部变量之前,一定要显式赋值。
- 特别地:形参在调用时,赋值即可。
- 在内存中加载的位置,亦各不相同。
- 属性:加载到堆空间中(非 static)
- 局部变量:加载到栈空间
- 在类中声明的位置不同
举例
public class UserTest {
public static void main(String[] args){
// 创建实例调用user
User u1 = new User();
System.out.println(u1.name);// null
System.out.println(u1.age); //0
u1.talk("English"); //实参
}
}
class User{
// 属性或成员变量
String name; //不加Private 或public即为缺省
public int age;
boolean isMale;
// 方法
public void talk(String language){ // 形参 也是局部变量
System.out.println("Talking " + language);
}
public void eat(){
String food = "饼"; // 局部变量
System.out.println("he likes" + food);
}
}
练习
/*
创建学生类,并调用方法返回其信息
*/
public class StudentTest {
public static void main(String[] args){
Student s1 = new Student();
s1.name = "zhangsan";
s1.age = 24;
s1.say();
}
}
// 创建学生类
class Student{
String name;
int age;
String major;
String interests;
public void say(){
System.out.println("This Student'name is " + name + " " + age + " years old");
}
}
04 类的成员之二:方法
方法定义
什么是方法(method 、函数)
- 方法 是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中也称为函数或过程。
- 将功能封装为方法的目的: 可以实现代码重用,简化代码
- Java 里的方法不能独立存在,所有的方法必须定义在类 里。
举例
public class Person{
private int age;
public int getAge(){ // 声明方法 getAge()
return age;
}
public void setAge(int i){ // 声明方法 setAge
age= i; // 将参数 i 的值赋给类的成员变量 age
}
}
文字说明
/*
* 类中方法的声明和使用
*
* 方法:描述类应该具有的功能。
* 比如:Math类:sqrt()\random() \...
* Scanner类:nextXxx() ...
* Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...
*
* 1.举例:
* public void eat(){}
* public void sleep(int hour){}
* public String getName(){}
* public String getNation(String nation){}
*
* 2. 方法的声明:权限修饰符 返回值类型 方法名(形参列表){
* 方法体
* }
* 注意:static、final、abstract 来修饰的方法,后面再讲。
*
* 3. 说明:
* 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
* Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说
*
* 3.2 返回值类型: 有返回值 vs 没有返回值
* 3.2.1 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用
* return关键字来返回指定类型的变量或常量:“return 数据”。
* 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要
* 使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
*
* 3.2.2 我们定义方法该不该有返回值?
* ① 题目要求
* ② 凭经验:具体问题具体分析
*
* 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
* 3.4 形参列表:方法名可以声明0个、1个,或多个形参。
* 3.4.1 格式:数据类型1 形参1,数据类型2 形参2,...
*
* 3.4.2 我们定义方法时,该不该定义形参?
* ① 题目要求
* ② 凭经验,具体问题具体分析
* 3.5 方法体:方法功能的体现。
* 4. return关键字的使用:
* 1.使用范围:使用在方法体中
* 2.作业:① 结束方法
* ② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
* 3.注意点:return关键字后不可声明执行语句。
* 5. 方法的使用中,可以调用当前类的属性或方法。
* 特殊的:方法A中又调用了方法A:递归方法。
* 方法中不能定义其他方法。
*/
代码举例一
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "Jerry";
p1.age = 17;
p1.sex = 1;
p1.study();
p1.showAge();
int newAge = p1.addAge(2);
System.out.println(p1.name + "的年龄为" + newAge);
System.out.println(p1.age); //19
//*******************************
Person p2 = new Person();
p2.showAge(); //0
p2.addAge(10);
p2.showAge(); //10
p1.showAge(); //20
}
}
class Person{
// 类的属性
String name;
int age;
int sex;
// 定义方法
public void study(){
System.out.println("Studying");
}
public void showAge(){
System.out.println("今年 " + age + " 岁");
}
public int addAge(int i){
age += 1;
return age;
}
}
练习二(方法)
public class MethodTesr {
public static void main(String[] args) {
// 方法必须写在类中,且在调用之前要新建一实例
MethodTesr test = new MethodTesr();
test.Print();
}
public void Print(){
for (int i = 0; i< 8; i++){
for(int j = 0; j< 10; j++){
System.out.print("*");
}
System.out.println();
}
}
}
public class MethodTesr {
public static void main(String[] args) {
// 方法必须写在类中,且在调用之前要新建一实例
MethodTesr test = new MethodTesr();
int area = test.Printarea();
System.out.println(area);
}
public int Printarea(){
for (int i = 0; i< 8; i++){
for(int j = 0; j< 10; j++){
System.out.print("*");
}
System.out.println();
}
return 10 * 8;
}
}
练习三(对象数组)
/*
定义类 Student ,包含三个属性:学号 number(int) ,年级 state(int) ,成绩
score(int) 。 创建 20 个学生对象,学号为 1 到 20 ,年级和成绩都由随机数 确定。
问题一:打印出 3 年级 (state 值为 3 )的学生信息 。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
*/
public class StudentTest {
public static void main(String[] args){
Student[] student = new Student[20]; //声明一个Student类型的数组
for(int i = 0; i< student.length ; i++) {
student[i] = new Student(); // 创建实例
student[i].number = i + 1; // 学号
student[i].score = (int) (Math.random() * (100 + 1)); // 0-100
student[i].state = (int) (Math.random() * 6 + 1);// 1-6
// 打印年级为3 的学生信息
if (student[i].state == 3) {
String info = student[i].info();
System.out.println(info);
}
}
System.out.println();
// 冒泡排序成绩
for (int i = 0; i < student.length; i++){
for(int j = 0 ; j < student.length - 1 - i; j++){
if (student[j].score < student[j+1].score){ //冒泡排序是内层排序
// 这里要交换student对象,不是数值
Student temp = student[j]; // 新建一个Student对象用于储存交换值
student[j] = student[j+1];
student[j+1] = temp;
}
}
}
// 遍历学生信息
for (int i = 0; i < student.length; i++){
System.out.println(student[i].info());
}
}
}
// 创建学生类
class Student{
int number;
int state;
int score;
public String info(){
return "学号 " + number + " 年级 " + state + " 成绩 " + score;
}
}
练习三的优化(重构方法)
public class StudentTest2 {
public static void main(String[] args) {
Student2[] student = new Student2[20]; //声明一个Student类型的数组
for (int i = 0; i < student.length; i++) {
student[i] = new Student2(); // 创建实例
student[i].number = i + 1; // 学号
student[i].score = (int) (Math.random() * (100 + 1)); // 0-100
student[i].state = (int) (Math.random() * 6 + 1);// 1-6
//
}
StudentTest2 test = new StudentTest2(); // 调用类中的方法前要实例化这个类
test.search(student, 3); // 实参也是数组和int型的数值
System.out.println();
test.bubbleSort(student); // 实参也为一个数组
test.print(student);
}
// 构造方法
// 遍历数组
public void print(Student2[] student) { // 形参为一个数组
for (int i = 0; i < student.length; i++) {
System.out.println(student[i].info());
}
}
// 打印为3
public void search(Student2[] student, int state) { // 形参为数组和int 型的数值
for (int i = 0; i < student.length; i++) {
if (student[i].state == state) {
String info = student[i].info();
System.out.println(info);
}
}
}
// 排序
public void bubbleSort(Student2[] student) {
for (int i = 0; i < student.length; i++) {
for (int j = 0; j < student.length - 1 - i; j++) {
if (student[j].score < student[j + 1].score) {
// 交换student对象
Student2 temp = student[j];
student[j] = student[j + 1];
student[j + 1] = temp;
}
}
}
//
}
}
class Student2 {
int number;
int state;
int score;
public String info() {
return "学号 " + number + " 年级 " + state + " 成绩 " + score;
}
}
4.2 对象数组的内存解析
/*引用类型的变量,只可能存储量两类值:null或地址值(含变量类型)*/
Student[] stus= newStudent[5]; //Student类型的数组
stus[0] = new Student();
sysout(stus[0].state);//1
sysout(stus[1]);//null
sysout(stus[1].number);//异常
stus[1] = new Student();
sysout(stus[1].number);//0
class Student{
int number;//学号
int state = 1;//年级
int score;//成绩
}
堆:存放new出来的东西
4.3 匿名对象的使用
- 理解:我们创建的对象,没有显示的赋值给一个变量名。即为匿名对象。
- 特征:匿名对象只能调用一次。
使用
public class InstanceTest {
public static void main(String[] args) {
// 实例对象
Phone p = new Phone();
// p = null;
System.out.println(p);
p.sendEmail();
p.playGame();
//匿名对象 不给实例出来的对象命名
// new Phone().sendEmail();
// new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice(); //0.0
//*******************************
PhoneMall mall = new PhoneMall();
// mall.show(p);
//匿名对象的使用
mall.show(new Phone());
}
}
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
class Phone{
double price; //价格
public void sendEmail(){
System.out.println("发邮件");
}
public void playGame(){
System.out.println("打游戏");
}
public void showPrice(){
System.out.println("手机价格为:" + price);
}
}
4.5 自定义数组的工具类
public class ArrayUtil {
/*
* 自定义数组工具类
*/
// 求数组的最大值
public int getMax(int[] arr) {
int maxValue = arr[0];
for (int i = 1; i < arr.length; i++) {
if (maxValue < arr[i]) {
maxValue = arr[i];
}
}
return maxValue;
}
// 求数组的最小值
public int getMin(int[] arr) {
int minValue = arr[0];
for (int i = 1; i < arr.length; i++) {
if (minValue > arr[i]) {
minValue = arr[i];
}
}
return minValue;
}
// 求数组总和
public int getSum(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
// 求数组平均值
public int getAvg(int[] arr) {
int avgValue = getSum(arr) / arr.length;
return avgValue;
}
// 反转数组
public void reverse(int[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - i - 1];
arr[arr.length - i - 1] = temp;
}
}
// 复制数组
public int[] copy(int[] arr) {
int[] arr1 = new int[arr.length]; //复制数组
for (int i = 0; i < arr1.length; i++) {
arr1[i] = arr[i];
}
return null;
}
// 数组冒泡排序
public void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 遍历数组
public void print(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println("]");
}
// 查找指定元素
public int getIndex(int[] arr, int dest) {
//线性查找
for (int i = 0; i < arr.length; i++) {
if (dest==arr[i]) {
return i;
}
}
return -1; // 没找到的化反回-1
}
}
对工具组测试
public class ArrayUtilTest {
public static void main(String[] args) {
ArrayUtil util = new ArrayUtil();
int[] arr = new int[]{32,5,26,74,0,96,14,-98,25};
int max = util.getMax(arr);
System.out.println("最大值为:" + max);
// System.out.print("排序前:");
// util.print(arr);
//
// util.sort(arr);
// System.out.print("排序后:");
// util.print(arr);
System.out.println("查找:");
int index = util.getIndex(arr, 5);
if(index > 0){
System.out.println("找到了,索引地址:" + index);
}else{
System.out.println("没找到");
}
}
}
4.6 方法的重载
重载的概念
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
重载特点
与返回值类型无关,只看参数列表,且参数列表必须不同。参数个数或参数类型 。调用时, 根据方法参数列表的不同来区别。
示例
- //返回两个整数的和
- int add( int x,int y){return x+y
- //返回三个整数的和
- int add( int x,int y,int z){return x+y+z
- //返回两个小数的和
- double add(double x,double y){return x+y
public class OverloadTest {
public static void main(String[] args){
OverloadTest test = new OverloadTest();
test.getSum(1,2);//3
test.getSum(1.0,2.0);//double
}
// 以下方法重载getSum()
public void getSum(int i, int j){
System.out.println(3);
}
public void getSum(float i, float j){
System.out.println(3.0);
}
public void getSum(double i, double j){
System.out.println("double");
}
}
4.7 可变参数的形参
JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定义能和多个实参相匹配的形参
。从而,可以用一种更简单的方式,来传递个数可变的实参。
说明
- 声明格式: 方法名 (参数的类型名…参数名)
- 可变 参数:方法参数部分指定类型的参数个数是可变 多 个: 0 个, 1 个或多个
- 可变 个数形参的方法与同名的方法之间,彼此构成重载
- 可变 参数方法的使用与方法参数部分使用数组是一致的
- 方法 的参数部分有可变形参,需要放在形参声明 的 最后
- 在一个方法的形参位置,最多只能声明一个可变个数形参
举例
public class MethodArgs {
public static void main(String[] args) {
MethodArgs arrgs = new MethodArgs();
arrgs.show(12);
arrgs.show(new String[] {"AA", "BB","CC"});
}
// 下面的三个方法彼此构成重构
public void show(int i){
}
public void show(String... strs){ // 可变参数使用方法参数部分与数组一致
System.out.println("show(String ...strs)");
for(int j = 0; j < strs.length ; j++){
System.out.println(strs[j]);
}
}
public void show(int i, String...strs){
}
}
4.8 方法参数的值传递机制
关于变量的赋值
Java里方法的参数传递方式只有一种: 值传递 。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
public static void main(String[] args) {
// 基本数据类型
int m = 10;
int n = m;
System.out.println("m = " + m + "," + "n = " + n); // m= 10,n=10
n = 20;
System.out.println("m = " + m + "," + "n = " + n);// m=10.n=20
// 引用数据类型
Order o1 = new Order();
o1.oderId = 1001;
Order o2 = o1; //赋值后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体
System.out.println("o1.orderId = " + o1.oderId + ",o2.orderId = " + o2.oderId);
// o1.orderId = 1001,o2.orderId = 1001
o2.oderId = 1002;
System.out.println("o1.orderId = " + o1.oderId + ",o2.orderId = " + o2.oderId);
// o1.orderId = 1002,o2.orderId = 1002
}
}
class Order{
int oderId;
}
4.8.1 基本数据类型的参数传递
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m = " + m + " n= " + n); // 10, 20
ValueTransferTest1 test = new ValueTransferTest1();
test.swap(m, n);
// 交换后数值
System.out.println("m = " + m + " n= " + n);
// 10, 20 这里只交换了swap内的参数,main中的mn 不受影响
}
public void swap(int m,int n){
int temp = m;
m = n;
n =temp;
}
}
4.8.2 引用数据类型的值传递
如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值。
public class ValueTest {
/*
* 如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值。
*/
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println("m = " + data.m + ", n = " + data.n); //10 20
ValueTest test = new ValueTest();
test.swap(data);
System.out.println("m = " + data.m + ", n = " + data.n);// 20 10
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
练习-> 确定输出结果
public class TransferTest3{
public static void main(String args[]){
TransferTest3 test=new TransferTest3();// 在堆中添加一个新的对象
test.first();
}
public void first(){
int i=5;
Value v=new Value();
v.i=25;
second(v,i); // 运行完second之后,second中定义的变量就出栈了
System.out.println(v.i);
}
public void second(Value v,int i){
i=0;
v.i=20;
Value val=new Value();
v=val;
System.out.println(v.i+" "+i);
}
}
class Value {
int i= 15;
}
// 15,0,20
4.8.3 练习2
public static void method(int a,int b){
a = a * 10;
b = b * 20;
System.out.println(a);
System.out.println(b);
System.exit(0); // 终止程序
}
4.8.3 练习三
/*
* 微软:
* 定义一个int型的数组:int[] arr = new int[]{12,3,3,34,56,77,432};
* 让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组。
*/
//错误写法
for(int i= 0;i < arr.length;i++){
arr[i] = arr[i] / arr[0];
}
//正确写法1
for(int i = arr.length –1;i >= 0;i--){
arr[i] = arr[i] / arr[0];
}
//正确写法2
int temp = arr[0];
for(int i= 0;i < arr.length;i++){
arr[i] = arr[i] / temp;
}
4.8.4 练习四
public class Test {
public static void main(String[] args) {
/*
* int[] arr = new int[10];
* System.out.println(arr);//地址值?
*
* char[] arr1 = new char[10];
* System.out.println(arr1);//地址值?
*/
int[] arr = new int[]{1,2,3};
//传进去的是一个Object的对象
System.out.println(arr);//地址值
char[] arr1 = new char[]{'a','b','c'};
//传进去的是一个数组,直接char型输出为数组
System.out.println(arr1);//abc
}
}
这里是因为println的重载,针对char[]类型的输出
String s1 = "HElloworld1234";
chs = s1.toCharArray(); // 转换为char型数组
System.out.println(chs);
System.out.println("前边加上字符输出的是地址:"+chs);
System.out.println("Arrays.toString(ch)以数组形式输出:"+Arrays.toString(chs));
/*
输出:
HElloworld1234
前边加上字符输出的是地址:[C@15db9742
Arrays.toString(ch)以数组形式输出:[H, E, l, l, o, w, o, r, l, d, 1, 2, 3, 4]
*/
4.8.5 练习五:将对象作为参数传递给方法
public class Test6 {
public static void main(String[] args){
PassObject object = new PassObject();
Circle c = new Circle();
object.printAreas(c, 6);
System.out.println("new redius " + c.radius);
}
}
// ciecle类
class Circle {
double radius; //半径
//返回圆的面积
public double findArea(){
return (double)(radius * radius * Math.PI);
}
}
// passobject类
class PassObject{
public void printAreas(Circle c, int time){
System.out.println("Redius" + "\t\t" + "Area");
for (int i = 1; i <= time; i++){
c.radius = i;
System.out.println(i + "\t\t" + c.findArea());
}
c.radius = time + 1;
}
}
4.9 递归方法的调用
- 递归方法:一个方法体内调用它自身。方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
public class RecursionTest {
public static void main(String[] args) {
// 例1:计算1-100之间所有自然数的和
// 方法1:
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("sum = " + sum);
// 方法2:
RecursionTest test = new RecursionTest();
int sum1 = test.getSum(100);
System.out.println("sum1 = " + sum1);
}
// 例1:计算1-n之间所有自然数的和
public int getSum(int n) {
if (n == 1) {
return 1;
} else {
return n + getSum(n - 1);
}
}
// 例2:计算1-n之间所有自然数的乘积
//归求阶乘(n!)的算法
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
}
}
}
4.9.2 练习一 求f(10)
已知 一个数列: f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),其中n 是大于 0 的整数,求 f(10) 的值 。
public class RecursionTest {
public static void main(String[] args) {
int value = test.f(10);
System.out.println(value);
}
//例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
if(n == 0){
return 1;
}else if(n == 1){
return 4;
}else{
return 2*f(n-1) + f(n-2);
}
}
//例4:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),
//其中n是大于0的整数,求f(10)的值。
public int f1(int n){
if(n == 20){
return 1;
}else if(n == 21){
return 4;
}else{
//return 2*f1(n-1) + f1(n-2);// 超出内存限制,递归占用大量内存
return f1(n + 2) - 2*f1(n + 1);
}
}
}
05 封装与隐藏(针对类的属性)
我们程序设计追求“高内聚,低耦合”。
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用
隐藏对象内部的复杂性,只对外公开简单的接口。
便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
Java中通过将数据声明为私有的 (private) 再提供公共的 public方法 getXxx 和 setXxx 实现对该属性的操作 以实现下述目的:
- 隐藏 一个类中 不需要对外提供的 实现细节;
- 使用者只能通过事先定制好的 方法来访问数据 可以方便地加入控制逻辑限制对属性的不合理操作;
- 便于修改增强代码的可维护性;
package OOP_NEW;
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "大黄";
// a.age = 1;
// a.legs = 4;//The field Animal.legs is not visible 不能直接调用
a.eat();
// a.legs = -4;
// a.setLegs(6);
a.setLegs(-6);
// a.legs = -4;//The field Animal.legs is not visible
a.eat();
System.out.println(a.name);
System.out.println(a.getLegs());
}
}
class Animal{
String name;
private int age;
private int legs;
//对于属性的设置 get/set
public void setLegs(int l){
if(l >=0 && l%2==0){
legs = 1;
}else{
legs = 0;
}
}
public int getLegs(){
return legs;
}
public void eat(){
System.out.println("eating");
}
// 对于age的get set方法
public int getAge(){
return age;
}
public void setAge(int a){
age = a;
}
}
5.1 四种权限修饰符的理解与测试
Java 权限修饰符public、protected、default(缺省)、private
置于类的成员定义前,用来限定对象对该类成员的访问权限
对于 class 的权限修饰只可以用 public 和 default(缺省)。
- public 类可以在任意地方被访问。
- default 类只可以被同一个包内部的类访问
代码举例
public class Order {
private int orderPrivate;
int orderDefault;
public int orderPublic;
private void methodPrivate(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
void methodDefault(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
public void methodPublic(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
}
OrderTest(在相同包内其他类文件调用Order)
public class OrderTest {
public static void main(String[] args) {
Order order = new Order(); //可以直接设计Order实例
order.orderDefault = 1;
order.orderPublic = 2;
//出了 Order 类之后,private的结构就不可调用了
// order.orderPrivate = 3;//The field Order.orderPrivate is not visible
order.methodDefault();
order.methodPublic();
//出了 Order 类之后,私有的结构就不可调用了
// order.methodPrivate();//The method methodPrivate() from the type Order is not visible
}
}
在相同项目不同包内调用Order
import github.Order;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 2;
//出了 Order 包之后,private的结构、Default的属性结构就不可调用了
// order.orderDefault = 1;
// order.orderPrivate = 3;//The field Order.orderPrivate is not visible
order.methodPublic();
//出了 Order 类之后,私有的结构、缺省的方法结构就不可调用了
// order.methodDefault();
// order.methodPrivate();//The method methodPrivate() from the type Order is not visible
}
}
06 构造器(构造类的方法)
6.1 构造器的理解
特征
- 它具有与类相同的名称
- 它不声明返回值类型。(与声明为 void 不同)
- 不能被 static 、 final 、 synchronized 、 abstract 、 native 修饰,不能有return 语句返回 值
作用:创建对象;给对象的属性进行初始化
- 如: Order o = new Order ()(); Person p = new Person (“Peter”,15
说明
1.如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器。
2.定义构造器的格式:
* 权限修饰符 类名(形参列表) { }
3.一个类中定义的多个构造器,彼此构成重载。
4.一旦显示的定义了类的构造器之后,系统不再提供默认的空参构造器。
5.一个类中,至少会有一个构造器 。
public class PersonTest1 {
public static void main(String[] args) {
Person1 person = new Person1(); //构造器 用于初始化对象
person.eat();
Person1 person1 = new Person1("zhangsan");
System.out.println(person1.name);
}
}
class Person1{
// 属性
String name;
int age;
// 构造器,一个类中可以有多个构造器,彼此构成重载
public Person1(){
System.out.println("Person()");
}
public Person1(String n){
name = n;
}
public Person1(String n, int a){
name = n;
age = a;
}
// 方法
public void eat(){
System.out.println("人吃饭");
}
public void study(){
System.out.println("人学习");
}
}
6.2 构造器练习
public class PersonTest1 {
public static void main(String[] args) {
Person1 person = new Person1(); //构造器 用于初始化对象
person.setName("zhangsan");
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
class Person1{
// 属性
private String name;
private int age;
// 构造器,一个类中可以有多个构造器,彼此构成重载
public Person1(){
age = 18; //初始化所有人年龄为18
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 120 || age < 0) {
age = -1;
} else {
age = age;
}
}
public String getName() {
return name;
}
public void setName(String name) {
name = name;
}
// 方法
public void eat(){
System.out.println("人吃饭");
}
public void study(){
System.out.println("人学习");
}
}
6.3 属性赋值的过程
/*
* 总结:属性赋值的先后顺序
*
* ① 默认初始化值
* ② 显式初始化
* ③ 构造器中赋值
* ④ 通过"对象.方法" 或 “对象.属性”的方式,赋值
*
* 以上操作的先后顺序:① - ② - ③ - ④
*
*/
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);
u1.setAge(3);
System.out.println(u1.age);
}
}
class User{
String name;
int age = 1;
public User(){
}
public User(int a){
age = a;
}
public void setAge(int a){
age = a;
}
}
07 关键词:this的使用
this是什么
- 它在方法内部使用,即这个方法所属对象的引用;
- 它在构造器内部使用,表示该构造器正在初始化的对象。
在类的方法中
在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性和方法。 通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名,我们必须显式 的使用"this.变量"的方式,表明此变量是属性,而非形参。
在类的构造器中
在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用正在创建的对象属性和方法。
但是,通常情况下,我们都选择省略“this.”。特殊情况下,如果构造器的形参和类的属性同名,我们必须显式 的使用"this.变量"的方式,表明此变量是属性,而非形参。
this 调用构造器
- 我们可以在类的构造器中,显式的使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
- 构造器中不能通过"this(形参列表)"的方式调用自己。
- 如果一个类中声明了n个构造器,则最多有n -1个构造器中使用了"this(形参列表)"。
- "this(形参列表)"必须声明在类的构造器的首行!
- 在类的一个构造器中,最多只能声明一个"this(形参列表)"。
代码举例
public class PersonTest1 {
public static void main(String[] args) {
Person1 p1 = new Person1();
p1.setAge(1);
System.out.println(p1.getAge());
p1.eat();
System.out.println();
Person1 p2 = new Person1("jerry", 20);
System.out.println(p2.getAge());
}
}
class Person1{
// 属性
private String name;
private int age;
// this在构造器中使用
public Person1(){
this.eat();
this.age = 18; //初始化所有人年龄为18
String info = " Person 初始化";
System.out.println(info);
}
public Person1(String name){
this();
this.name = name;
}
public Person1(int age){
this();
this.age = age;
}
public Person1(String name, int age){
this(age);// 必须在构造器首行,构造器另一种方法
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 120 || age < 0) {
age = -1;
} else {
this.age = age;
}
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
// 在方法中使用this
public void eat(){
System.out.println("人吃饭");
this.study();
}
public void study(){
System.out.println("人学习");
}
}
7.2 练习一
写一个名为 Account 的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:
账号 id ,余额 balance ,年利率 annualInterestRate ;包含的方法:访问器方法 getter 和 setter方法,取款方法 with d raw()raw(),存款方法 deposit() 。
public class Account {
private int id;
private double balance;
private double annualInterrestRate;
// 访问器方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterrestRate() {
return annualInterrestRate;
}
public void setAnnualInterrestRate(double annualInterrestRate) {
this.annualInterrestRate = annualInterrestRate;
}
// 方法
public void withdraw(double amount){ // 取钱
if(amount > this.balance){
System.out.println("余额不足");
}else{
this.balance -= amount;
}
}
public void deposit(double amount){ // 存钱
if(amount < 0){
System.out.println("你在逗我");
}else{
this.balance += amount;
System.out.println("成功存入");
}
}
}
创建customer类
public class Customer {
private String firstName;
private String lastName;
private Account account; // 声明类的属性
// 构造器
public Customer(String f, String l){
this.firstName = f;
this.lastName = l;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
测试(包含main方法的主程序)
/*
写一个测试程序。
* (1)创建一个 Customer,名字叫 Jane Smith, 他有一个账号为 1000,余额为 2000 元,年利率为 1.23%的账户。
* (2)对 Jane Smith 操作。存入 100 元,再取出 960 元。再取出 2000 元。
* 打印出 Jane Smith 的基本信息
* 成功存入:100.0
* 成功取出:960.0
* 余额不足,取款失败
* Customer [Smith, Jane] has a account: id is 1000,
* annualInterestRate is 1.23%, balance is 1140.0
*/
public class Custmertest {
public static void main(String[] args) {
Customer customer = new Customer("Jane", "Smith");
Account account = new Account();
account.setId(1000);
account.setBalance(2000);
account.setAnnualInterrestRate(0.0123);
customer.setAccount(account);
customer.getAccount().deposit(100); //主要掌握多层调用
customer.getAccount().withdraw(960);
customer.getAccount().withdraw(2000);
System.out.println("Custmor " + customer.getFirstName() + " " + customer.getLastName() +
"has an Acount with balance " + customer.getAccount().getBalance() + " the id is "+
customer.getAccount().getId());
}
}
8 关键词: package 、import的使用
8.1 package介绍
package 关键字的使用
package 语句作为 Java 源文件的第一条语句,指明该文件中定义的类所在的包。 若缺省该语句,则指定为无名包 。它的格式为:package.顶层包名.子包名
包,属于标识符,遵循标识符的命名规则、规范"见名知意"每“.”一次,就代表一层文件目录。
- 补充:同一个包下,不能命名同名接口或同名类,不同包下,可以命名同名的接口、类。
Java中主要的包
1.java.lang----包含一些 Java 语言的核心类,如 String、Math、Integer、System 和 Thread,提供常用功能
2.java.net----包含执行与网络相关的操作的类和接口。
3.java.io----包含能提供多种输入/输出功能的类。
4.java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
5.java.text----包含了一些 java 格式化相关的类
6.java.sql----包含了 java 进行 JDBC 数据库编程的相关类/接口
7.java.awt----包含了构成抽象窗口工具集(abstractwindowtoolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。B/S C/S
8.2 MVC设计模式
8.3 import介绍
import:导入
- 在源文件中显式的使用import结构导入指定包下的类、接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构,则并列写出即可
- 可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构。
- 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
- 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
- 7.如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
- 8.import static组合的使用:调用指定类或接口下的静态的属性或方法.
import java.util.*;
import account2.Bank;
public class PackageImportTest {
public static void main(String[] args) {
String info = Arrays.toString(new int[]{1,2,3});
Bank bank = new Bank();
ArrayList list = new ArrayList();
HashMap map = new HashMap();
Scanner s = null;
System.out.println("hello");
UserTest us = new UserTest();
}
}