Java方法是语句的集合,他们在一起执行一个功能。
设计方法的原则:
方法包含一个方法头和一个方法体,以下内容是一个方法的所有部分:
修饰符 返回值类型 方法名(参数类型 参数名){
…
方法体
…
return 返回值; //return也是终止方法的语句
}
eg:public static void main(String []args){}
调用方法: 对象名.方法名(实参列表)
Java支持两种调用方法的方式,根据方法是否返回值来选择
int larger = max(23,43);
System.out.println("Hello,neo!");
public class Method{
public static void main(String []args){
int a = max(23,45);
System.out.print(a);
}
public static int max(int num1,int num2){
return num1>num2 ? num1 :num2;
}
}
**值传递(pass by value):**在调用函数时,将实际参数复制一份传递到函数中,在函数中对参数进行修改,不会影响到原来的实际参数;
引用传递(pass by reference):在调用函数时,将实际参数的地址直接传递到函数中。在函数中对参数进行的修改,会影响到实际参数;
Java传递数值参数,使用的是值传递,传递对象和动态创建String时,使用的是值传递。
值传递举例:
public class MyScanner {
public static void main(String[] args) {
// 基本数据类型
int i = 10;
add(i);
System.out.println("i = " + i);
System.out.println("==================");
// 引用数据类型中的String
String str = "你好";
append(str);
System.out.println("str : "+str);
System.out.println("==================");
String string = new String("Hello");
pass(string);
System.out.println("str:"+string);
}
public static void add(int num) {
num ++;
System.out.println("num = " + num);
}
public static void append(String str){
str += "=====";
System.out.println("string : " + str);
}
public static void pass(String str){
str = new String("world");
System.out.println("string:"+str);
}
}
//add函数中传入数值参数i,add 方法中对i进行操作,不会影响方法外i的值。
//append 函数中传入引用类型String的参数str,但是在方法中对str进行操作,也不会改变str自身在方法外的值。
// 输出结果
// num = 20
// i = 10
//==================
//string : 你好=====
//str : 你好
// ==================
// string:world
// str:Hello
引用传递举例
public class MyScanner {
public static void main(String[] args) {
// 引用数据类型中的String
StringBuilder string = new StringBuilder("Hello");
pass1(string);
System.out.println("str:"+string);
System.out.println("==================");
pass2(string);
System.out.println("str:"+string);
}
public static void pass1(StringBuilder str){
str = new StringBuilder("world");
System.out.println("string1:"+str);
}
public static void pass2(StringBuilder str){
str.append("!!!!");
System.out.println("string2:"+str);
}
}
// string1:world
// str:Hello
// ==================
// string2:Hello!!!!
// str:Hello!!!!
重载就是在 一个类中,函数名称相同但是形参不同的函数。
方法重载的规则:
实现理论:
public class Method{
public static void main(String []args){
int a = max(23,45);
double d = max(23.1,45.0);
System.out.println(a); //45
System.out.println(d); //45.0
}
public static int max(int num1,int num2){
return num1>num2 ? num1 :num2;
}
public static double max(double num1,double num2){
return num1>num2 ? num1 :num2;
}
}
在命令行中编译完成,运行的时候可以传入对应的参数
(以下代码在idea中点击绿色三角执行会直接结束)
public class Method1 {
public static void main(String []args){
for (int i = 0; i <args.length ; i++) {
// 数组长度 args.length
System.out.println("args["+i+"]:"+args[i]);
}
}
}
在命令行中先编译,再执行,传入参数,结果如下:
( 注意: 如果在命令行中进行运行的文件在包中,编译的时候可以在包目录下,但是执行的时候要在包目录之外,否则会找不到)
package com.dande.base;
import java.util.Scanner;
public class VariableParam {
public static void main(String[] args) {
double max1 = getMax(new double[] {12.3,45.6,67.0});
double max2 = getMax(13.4,56.7,78,98.2);
System.out.println(max1);
System.out.println(max2);
}
public static double getMax(double ...numbers){
if(numbers.length == 0){
System.out.println("There is no number!");
return 0.0;
}
double result = numbers[0];
for (int i = 0; i <numbers.length ; i++) {
if (numbers[i] > result){
result = numbers[i];
}
}
return result;
}
}
递归就是A方法调用A方法,自己调用自己!!
递归结构包括两部分:
递归实现小数字的阶乘
package com.dande.base;
public class Factorial {
public static void main(String[] args) {
Factorial fa = new Factorial();
int result = fa.factorial(5);
System.out.println(result);
}
public int factorial(int n){
if(n==1){
return 1;
}else{
return n*factorial(n-1);
}
}
}
计算器练习
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.print("请输入第一个操作数:");
double num1 = scanner.nextDouble();
System.out.print("请输入运算符(+ - * /):");
String operator = scanner.next();
System.out.print("请输入第二个操作数:");
double num2 = scanner.nextDouble();
double result = 0;
switch(operator) {
case "+":
result = num1 + num2;
break;
case "-":
result = num1 - num2;
break;
case "*":
result = num1 * num2;
break;
case "/":
result = num1 / num2;
break;
default:
System.out.println("无效的运算符");
break;
}
System.out.println(num1 + " " + operator + " " + num2 + " = " + result);
System.out.print("继续计算请按Y,退出请按其他键:");
String input = scanner.next();
if(!input.equals("Y")) {
break;
}
}
scanner.close();
}
}
package com.dande.base;
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
// 写一个计算器,实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现
/**
* 思路:
* 1.写四个方法,加减乘除
* 2.利用循环加switch进行用户交互
* 3.传递需要操作的操作数
* 4.输出结果
*/
System.out.println("请输入数据和运算符+,-,*,/,用,分隔:");
// double nums[] = new double[100];
Scanner scanner = new Scanner(System.in);
String temp1 = scanner.nextLine();
String[] s = temp1.split(",");
double[] nums = new double[s.length-1];
for (int i = 0; i <s.length-1 ; i++) {
nums[i] = Double.parseDouble(s[i]);
}
String operator = s[s.length-1];
switch (operator){
case "+":
show(nums);
add(nums);
break;
case "-":
show(nums);
reduce(nums);
break;
case "*":
show(nums);
multi(nums);
break;
case "/":
show(nums);
divide(nums);
break;
}
scanner.close();
}
public static void show(double...nums){
System.out.print("您输入的数据为:");
for (double i :nums) {
System.out.print(i+"\t");
}
System.out.println();
}
public static void add(double ...nums){
if (nums.length==0){
System.out.println("您输入了0个数字,结果为0!");
}
double result = 0;
for (int i = 0; i <nums.length ; i++) {
result +=nums[i];
}
System.out.println("他们的求和结果为:"+result);
}
public static void reduce(double ...nums){
if (nums.length==0){
System.out.println("您输入了0个数字,结果为0!");
}
double result = nums[0];
for (int i = 1; i <nums.length ; i++) {
result -=nums[i];
}
System.out.println("他们的作差结果为:"+result);
}
public static void multi(double ...nums){
if (nums.length==0){
System.out.println("您输入了0个数字,结果为0!");
}
double result = nums[0];
for (int i = 1; i <nums.length ; i++) {
result *=nums[i];
}
System.out.println("他们的求积结果为:"+result);
}
public static void divide(double ...nums){
if (nums.length==0){
System.out.println("您输入了0个数字,结果为0!");
}
double result = nums[0];
for (int i = 1; i <nums.length ; i++) {
if(nums[i] !=0){
result /=nums[i];
}else{
System.out.println("除数不能为0");
return ;
}
}
System.out.println("他们的相除结果为:"+result);
}
}
数组的定义
声明数组变量:
dataType[] arrayRefVar;
//首选方法(变量类型 变量名 = 变量的值;)dataType arrayRefVar[];
//效果相同但是不是首选创建数组:
dataType[] arrayRefVar = new dataType[arraySize];
数组元素访问:
获取数组长度:
arrays.length;
package com.dande.base;
public class ArrayDemo1 {
public static void main(String[] args) {
// 1.声明一个数组(在栈中开辟空间
int[] nums;
// 2.创建一个数组(动态分配内存空间,堆中开辟空间)
nums = new int[10];
// 3.给数组元素赋值,访问数组元素nums[i[
// 单独给每一个数组元素赋值,nums.length为数组长度
nums[0] =1;
nums[1] =2;
nums[2] =3;
nums[3] =4;
nums[4] =5;
// for (int i = 0; i
// nums[i] = i;
// }
// 声明创建赋值
int[] nums2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 4.访问数组元素 nums[i]
int result = 0;
for (int i = 0; i <nums.length ; i++) {
result +=nums[i];
}
System.out.println(result);
}
}
int [] a = {1,2,3};
Man[] mans = {new Man(1,1),new Man(2,2)};
int[] a = new int[2];
a[0] = 1;
a[1] = 2;
package com.dande.base;
public class ArrayDemo1 {
public static void main(String[] args) {
//静态初始化:创建+赋值
int[] a = {1,2,3,4,5};
System.out.println(a[0]); //1
// 动态初始化:包含默认初始化
int[] b = new int[10];
b[0] = 1;
System.out.println(b[0]); //1
System.out.println(b[1]); //0
System.out.println(b[2]); //0
}
}
package com.dande.base;
public class ArrayDemo1 {
public static void main(String[] args) {
// 数组下标
int[] a = new int[2];
System.out.println(a[2]); //java.lang.ArrayIndexOutOfBoundsException
}
}
ArrayIndexOutOfBoundsException:数组下标越界!!
package com.dande.base;
public class ArrayDemo1 {
public static void main(String[] args) {
// - for循环
// - 增强for循环(for-each循环)
// - 数组作为方法入参
// - 数组作为返回值
int[] arrays = {1,2,3,4,5,6,7};
int sum = 0;
int max = 0;
//for循环
for (int i = 0; i <arrays.length ; i++) {
sum +=arrays[i];
max = max > arrays[i] ? max : arrays[i];
}
System.out.println("The sum is "+sum +",The max is "+max);
printArr(arrays);
int[] reverseArray = reverse(arrays);
printArr(reverseArray);
}
//数组作为参数
public static void printArr(int[] array){
// for-each循环
for (int arr:array) {
System.out.print(arr+" ");
}
System.out.println();
}
//数组作为参数、数组作为返回值
public static int[] reverse(int[] array){
int[] result = new int[array.length];
for (int i = 0,j=array.length-1; i <array.length ; i++,j--) {
result[j] = array[i];
}
return result;
}
}
package com.dande.base;
public class ArrayDemo1 {
public static void main(String[] args) {
//多维数组
int a[][] = {{1,2,5,6},{1,2,4,6},{1,2,3,4,5}};
/**
* a[0] {1,2,5,6}
* a[1] {1,2,4,6}
* a[2] {1,2,3,4,5}
*/
printArr(a[0]);
System.out.println("====================");
for (int i = 0; i <a.length ; i++) {
for (int j = 0; j <a[i].length ; j++) {
System.out.print(a[i][j]+"\t");
}
System.out.println();
}
}
public static void printArr(int[] array){
for (int arr:array) {
System.out.print(arr+" ");
}
System.out.println();
}
}
package com.dande.base;
import java.util.Arrays;
public class ArrayDemo1 {
public static void main(String[] args) {
int[] a = {12,4,56,3,7,8,65,422};
int[] b = {12,4,56,3,7,9,65};
System.out.println(a); // [I@1540e19d
System.out.println(Arrays.toString(a)); //[12, 4, 56, 3, 7, 8, 65, 422]
Arrays.sort(a); //默认将数组从小到大排序
System.out.println(Arrays.toString(a)); //[3, 4, 7, 8, 12, 56, 65, 422]
Arrays.fill(a,1); //将数组中的所有元素都变为1
System.out.println(Arrays.toString(a)); //[1, 1, 1, 1, 1, 1, 1, 1]
Arrays.fill(a,2,5,0); //将数组中的2-5号元素,即a[2],a[3],a[4]变为0
System.out.println(Arrays.toString(a)); // [1, 1, 0, 0, 0, 1, 1, 1]
System.out.println(Arrays.equals(a,b)); //false
System.out.println(Arrays.binarySearch(a,7)); //-9(-数组长度-1)
System.out.println(Arrays.binarySearch(b,7)); //4 (元素所在位置的索引)
}
}
package com.dande.base;
import java.util.Arrays;
public class Bubble {
public static void main(String[] args) {
int[] a = {12, 3, 4, 5, 6, 45, 32, 234, 987};
Bubble(a);
System.out.println(Arrays.toString(a));
}
public static void Bubble(int[] a) {
int temp = 0;
// 外层循环,次数
for (int i = 0; i < a.length - 1; i++) {
//内层循环,交换数据
for (int j = 0; j < a.length-1- i; j++) {
if (a[j + 1] > a[j]) {
temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
}
}
冒泡排序的基本思想是通过相邻元素的比较和交换来将较大的元素逐渐向右移动至正确的位置。为了优化冒泡排序的性能,可以进行以下几个方面的改进:
设置标志位:在每一趟排序中,如果没有发生元素交换,则说明待排序数组已经有序,可以提前结束排序。
减少比较次数:在每一趟排序中,每次比较可以确定一个最大值,所以下一趟排序时,可以减少比较次数。具体做法是,在每一趟排序中记录下最后一次交换的位置,该位置之后的元素必然已经有序,下一趟排序时只需比较到该位置即可。
减少交换次数:冒泡排序每次交换都需要三次赋值操作,可以通过记录下最后一次交换的位置,来减少不必要的交换次数。具体做法是,在每一趟排序中记录下最后一次交换的位置,下一趟排序时,只需将待排序数组的长度设置为最后一次交换的位置即可
package com.dande.base;
import java.util.Arrays;
public class Bubble {
public static void main(String[] args) {
int[] b = {12, 3, 4, 5, 6, 45, 32, 234, 1023,45,987};
BubblePlus(b);
System.out.println(Arrays.toString(b));
}
public static void BubblePlus(int[] a) {
int temp = 0;
// 外层循环,次数
for (int i = 0; i < a.length - 1; i++) {
boolean flag = false;
//内层循环,交换数据
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j + 1] > a[j]) {
temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
flag = true;
}
}
if(!flag) break;
}
}
}
package com.dande.base;
public class ArrayDemo02 {
public static void main(String[] args) {
//1. 记录并打印原始数组 11行11列,0:无棋子;1:黑棋;2:白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
array1[7][3] = 1;
array1[2][8] = 2;
System.out.println("原始数组为:");
for (int i = 0; i <array1.length ; i++) {
for (int j = 0; j <array1[i].length ; j++) {
System.out.print(array1[i][j]+"\t");
}
System.out.println();
}
// 2. 获取原始数组中有效数字的个数
int sum = 0;
for (int i = 0; i <array1.length ; i++) {
for (int j = 0; j <array1[i].length ; j++) {
if(array1[i][j]!= 0) sum++;
}
}
System.out.println("有效数字个数:"+sum);
// 3. 创建稀疏数组
int[][] array2 = new int[sum+1][3];
array2[0][0] = array1.length;
array2[0][1] = array1.length;
array2[0][2] = sum;
//稀疏数组取值
int count= 0;
for (int i = 0; i <array1.length ; i++) {
for (int j = 0; j <array1[i].length ; j++) {
if(array1[i][j] !=0){
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
System.out.println("稀疏数组为:");
for (int i = 0; i <array2.length ; i++) {
System.out.println(array2[i][0]+"\t"
+array2[i][1]+"\t"
+array2[i][2]+"\t");
}
// 4. 还原稀疏数组
//创建数组
int[][] array3 = new int[array2[0][0]][array2[0][1]];
// 数组取值
for (int i = 1; i <array2.length ; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
System.out.println("还原后的数组:");
for (int i = 0; i <array3.length ; i++) {
for (int j = 0; j <array3[i].length ; j++) {
System.out.print(array3[i][j]+"\t");
}
System.out.println();
}
}
}
Java的核心思想就是面向对象编程(OOP)。
对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,需要使用面向对象的思路分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
面向对象编程(Object-Oriented Programming,OOP)
面向对象编程的本质: 以类的方式组织代码,以对象的组织(封装)数据。
抽象
面向对象的三大特性:封装、继承、多态
从认识论角度考虑是现有对象后有类。对象是具体的事物,类是抽象的,对对象的抽象。
从代码运行角度考虑是先有类后有对象。类是对象的模板。
静态方法和非静态方法
package com.dande.oop;
public class Demo01 {
public static void main(String[] args) {
// 静态方法可以直接调用
produce();
Student.speak();
//非静态方法要通过类的实例化进行调用
Demo01 demo01 = new Demo01();
demo01.conduct();
Student student = new Student();
student.run();
}
public static void produce(){
System.out.println("This is a static method!");
}
public void conduct(){
System.out.println("This is a method!");
}
}
class Student {
public static void speak(){
System.out.println("speaking!");
}
public void run(){
System.out.println("Running!");
}
}
值传递和引用传递
package com.dande.oop;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class Demo02 {
public static void main(String[] args) {
// 值传递
int a = 18;
System.out.println(a); //18
passValue(a);
System.out.println(a); //18
// 引用传递:对象(本质传递的还是值)
Person person = new Person();
System.out.println(person.name); //null
passRef(person);
System.out.println(person.name); //yiwa
}
public static void passValue(int a){
a++;
}
public static void passRef(Person p){
p.name = "yiwa";
}
}
class Person{
String name;
int age;
public static void speak(){
System.out.println("Hello");
}
}
package com.dande.oop;
public class Application {
// 一个项目应该只有一个 main主程序,是项目的入口
public static void main(String[] args) {
// 类是抽象的,需要进行实例化,类实例化后会返回一个自己的对象。
// Employee实例化之后返回一个employee对象
// idea 快捷键:new Employee alt+enter
Employee Lily = new Employee();
Lily.age = 23;
Lily.name = "Lily";
Lily.introduce();
Employee Anna = new Employee();
Anna.age = 24;
Anna.name = "Anna";
Anna.introduce();
}
}
//员工类
class Employee{
//属性:字段
String name;
int age;
double salary;
//方法
public void introduce(){
//this表示当前类
System.out.println("Hello,my name is "+ this.name+",and I'm "+ this.age);
}
}
package com.dande.oop;
public class Application {
// 一个项目应该只有一个 main主程序,是项目的入口
public static void main(String[] args) {
Employer aaa = new Employer();
Employer bbb = new Employer("Janny");
Employer ccc = new Employer("Tom",24);
Employer ddd = new Employer("Jack",37,32000);
aaa.introduce();
bbb.introduce();
ccc.introduce();
ddd.introduce();
}
}
//雇主类
class Employer {
String name;
int age;
double salary;
//1.默认的无参构造方法,写了有参构造方法之后必须要把无参构造方法显式定义出来
public Employer(){}
//2. 只有一个参数的构造方法
public Employer(String name) {
this.name = name;
}
// 3.含有两个参数的构造方法
public Employer(String name, int age) {
this.name = name;
this.age = age;
}
// 4. 包含所有参数的构造方法
public Employer(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
//其他方法
public void introduce() {
//this表示当前类
System.out.println("Hello,my name is " +
this.name + ",and I'm " +
this.age+",My salary is "+this.salary);
}
}
程序从Application 类中进入,main方法以及常量"旺财"都在方法区,(年龄3 是int类型数据),类模板Pet也在方法区,main方法在栈中执行,创建两个引用变量名,实际指向的是堆中开辟的内存空间,存放实际的对象,对象可以直接调用静态方法区中的static方法。
package com.dande.oop;
public class Application2 {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
dog.shout();
Pet cat = new Pet();
cat.shout();
Pet.eat();
dog.eat();
cat.eat();
}
}
class Pet{
String name;
int age;
public void shout(){
System.out.println(this.age+"岁的"+this.name+" is shouting!");
}
public static void eat(){
System.out.println("吃饭啦!!!");
}
}
整体封装留一个接口供外部调用
示例代码:
idea快捷键:alt+Fn+insert设置Getter和Setter
package com.dande.oop;
import com.dande.oop.demo01.Student;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(102); // 不合法的输入数据
System.out.println(student.getName()); // 张三
System.out.println(student.getAge()); //3
}
}
Student类
package com.dande.oop.demo01;
// 类 private:私有
public class Student {
// 属性私有
private String name;
private int age;
private char sex;
// 提供可以操作属性的方法:public set、get方法
//get方法,获取数据
public String getName() {
return name;
}
public int getAge() {
return age;
}
public char getSex() {
return sex;
}
//set 方法,给数据设置值
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if(age>0 && age<100) {
this.age = age;
}else{
this.age = 3; // 对于不合法的传入参数做处理
}
}
public void setSex(char sex) {
this.sex = sex;
}
}
封装的意义:
final
修饰的类不能继承,没有子类public class Teacher extends Person {
}
this和supper的区别:
子类和父类的方法一致,方法体不同
方法名必须相同
参数列表必须相同
修饰符: 范围可以扩大但是不能缩小public>protected>default>private
抛出的异常:范围可以缩小但是不能扩大
子类重写父类的方法,使用@Override
注解(有功能的注释)
静态方法的调用只和左边定义的数据类型有关
package com.dande.oop;
import com.dande.oop.demo01.Teacher;
import com.dande.oop.demo01.Person;
public class Application {
public static void main(String[] args) {
Teacher teacher1 = new Teacher();
teacher1.print(); //I am Teacher !
teacher1.speak(); // Teacher speaking!
// 父类的引用指向了子类
// 静态方法的调用只和左边定义的数据类型有关
//对象能执行哪些方法主要看对象左边的类型
Person teacher2 = new Teacher();
teacher2.print(); //I am Person !
teacher2.speak(); // Teacher speaking!
}
}
package com.dande.oop.demo01;
//父类
public class Person {
public static void print(){
System.out.println("I am Person !");
}
public void speak(){
System.out.println("Person speaking!");
}
}
package com.dande.oop.demo01;
//子类
public class Teacher extends Person {
public static void print(){
System.out.println("I am Teacher !");
}
@Override //注解:有功能的注释
public void speak() {
// super.speak();
//子类重写了父类的方法
System.out.println("Teacher speaking!");
}
}
多态存在的条件:
注意:
Student s1 = new Student();
Student为子类,Person为父类Person s2 = new Student();
子类重写父类的方法,执行子类中的方法,父类不能调用子类独有的方法ClassCastException!
) Father f1 = new Son();
package com.dande.oop;
import com.dande.oop.demo01.Student;
import com.dande.oop.demo01.Person;
public class Application {
public static void main(String[] args) {
Student s1 = new Student(); //创建子类
Person s2 = new Student(); //父类的引用指向子类
s1.speak(); //student
s2.speak(); //student 子类重写了父类的方法,执行的是子类的方法
s1.exam(); //examing
// s2.exam(); //父类不能调用子类独有的方法
((Student)s2).exam(); //类型强转
}
}
package com.dande.oop.demo01;
//子类
public class Student extends Person {
@Override
public void speak() {
System.out.println("student");
}
public void exam(){
System.out.println("examing!");
}
}
package com.dande.oop.demo01;
//父类
public class Person {
public void speak(){
System.out.println("Person speaking!");
}
}
instanceof
用于测试对象是否是指定类型(类或者子类或者接口)的实例。package com.dande.oop;
import com.dande.oop.demo01.Student;
import com.dande.oop.demo01.Person;
import com.dande.oop.demo01.Teacher;
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person >Teacher
//Object > Person >Student
Object s1 = new Student();
System.out.println(s1 instanceof Student); //true
System.out.println(s1 instanceof Person); //true
System.out.println(s1 instanceof Object); //true
System.out.println(s1 instanceof Teacher); //false
System.out.println(s1 instanceof String); //false
System.out.println("==========================");
Person s2 = new Student();
System.out.println(s2 instanceof Student); //true
System.out.println(s2 instanceof Person); //true
System.out.println(s2 instanceof Object); //true
System.out.println(s2 instanceof Teacher); //false
// System.out.println(s2 instanceof String); //编译不通过
Student s3 = new Student();
System.out.println("======================");
System.out.println(s3 instanceof Student); //true
System.out.println(s3 instanceof Person); //true
System.out.println(s3 instanceof Object); //true
// System.out.println(s3 instanceof Teacher); //编译不通过
// System.out.println(s3 instanceof String); //编译不通过
System.out.println("=========================");
//如果变量为null,则instanceof比较结果为false
Student s4 = null;
System.out.println(s4 instanceof Student); //false
}
}
static(静态的)
修饰的属性和方法都是和类一起加载的,存放在堆中的方法区中的静态方法区内。
package com.dande.oop.demo02;
import java.sql.SQLOutput;
public class Student {
public String name;
public static double score;
public void run(){
go(); //非静态方法可以直接调用静态方法
System.out.println("run");
}
public static void go(){
// run(); 静态方法不能直接调用非静态方法
System.out.println("go");
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.score); // 0.0静态属性可以直接通过类名调用
// System.out.println(Student.name); // 非静态属性不能直接通过类名调用
System.out.println(s1.name); // null 非静态属性只能通过类的实例来调用
go(); //静态方法可以直接调用
Student.go(); // 静态方法也可以直接使用类名调用
// run();
// Student.run();
s1.run(); // 非静态方法只能通过类的实例对象来调用
}
}
静态代码块 static{}
,和 类一起加载,只执行一次
匿名代码块{}
,匿名代码块在创建对象的时候自动创建,常被用来赋初始值
静态代码块、匿名代码块和构造方法的执行顺序:静态代码块–>匿名代码块–>构造方法
package com.dande.oop.demo02;
public class Person {
// 匿名代码块,第二个执行,创建一个对象 执行一次
{
System.out.println("匿名代码块!");
}
// 静态代码块,第一个执行,只执行一次
static{
System.out.println("静态代码块!");
}
// 构造方法,第三个执行,创建一次对象执行一次
public Person(){
System.out.println("构造方法!");
}
public static void main(String[] args) {
Person p1 = new Person();
System.out.println("=================");
Person p2 = new Person();
System.out.println("=================");
Person p3 = new Person();
}
// 静态代码块!
// 匿名代码块!
// 构造方法!
// =================
// 匿名代码块!
// 构造方法!
// =================
// 匿名代码块!
// 构造方法!
}
静态导入包中的方法,可以直接使用
package com.dande.oop.demo01;
import static java.lang.Math.random;
import static java.lang.Math.round;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
// System.out.println(Math.random());
//静态导入包中的方法和变量之后在代码中直接调用
System.out.println(round(random()*10));
System.out.println(PI);
}
}
abstract
修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,该类就是抽象类。
package com.dande.oop.demo02;
public abstract class Action {
String name;
public void introduce(){ //抽象类中也可以有非抽象方法
System.out.println("自我介绍!");
}
public abstract void job(); // 抽象方法所在的类必须是抽象类,抽象方法只有方法的声明,没有方法体
}
package com.dande.oop.demo02;
public class A extends Action { // 继承抽象类的类必须要实现抽象类中的抽象方法,或者将子类也声明为抽象类
@Override
public void job() {
System.out.println("working!");
}
public static void main(String[] args) {
A a1 = new A();
a1.job();
}
}
思考:
Action.class文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.dande.oop.demo02;
public abstract class Action {
String name;
public Action() {
}
public void introduce() {
System.out.println("自我介绍!");
}
public abstract void job();
}
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有!
接口:只有规范,自己无法写方法 !!
约束和实现分离,面向接口编程.
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是。。则必须能。。的思想。”
接口的本质是规约,(像现实中的法律一样,指定好后大家都遵守)
声明类的关键字是class,声明接口的关键字是interface
implements
)implements
)来实现“多继承”userServiceImpl.java
package com.dande.oop.demo03;
public class userServiceImpl implements userService ,timer{ // 接口可以多重实现
@Override // 实现接口的类必须重写接口中的方法
public void add() {
}
@Override
public void delete() {
}
@Override
public int query() {
return 0;
}
@Override
public String update() {
return null;
}
@Override
public void cost() {
}
}
timer.java
package com.dande.oop.demo03;
public interface timer {
void cost();
}
userService.java
package com.dande.oop.demo03;
public interface userService {
public static final int SCNO = 10027; //接口中的属性默认都是 public static final修饰的常量
public abstract void add(); // 接口中的方法默认是public abstract的
void delete();
int query();
String update();
}
各种内部类的参考博文(博主“Java新生代”的文章)
内部类就是在一个类的内部定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类。
外部类对象.new 内部类()
。package com.dande.oop.demo04;
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
// 内部类可以获取外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
package com.dande.oop.demo04;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
// 通过这个外部类的实例化内部类
Outer.Inner inner = outer.new Inner();
inner.getID(); //10
}
}
外部类.内部类()
。package com.dande.oop.demo04;
public class Outer {
private static int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
public static class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
// 内部类可以获取外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
package com.dande.oop.demo04;
public class Application {
public static void main(String[] args) {
//静态内部类的实例化
Outer.Inner inner = new Outer.Inner();
inner.getID();
}
}
package com.dande.oop.demo04;
public class Outer {
public void method(){
// 局部内部类
class Inner{
public void in(){
}
}
}
}
package com.dande.oop.demo04;
public class Outer {
public static void main(String[] args) {
// 没有名字初始化类,不用将实例保存到变量中
new Person().eat();
}
}
class Person{
public void eat(){
System.out.println("chichichi");
}
}
Exception
)异常分类:
ERROR
:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,他们在编译时检查不到。异常处理:
java把异常当做对象来处理,并定义一个基类java.lang.Throwable
作为所有异常的超类。
在Java API 中已经定义了许多异常类,这些异常类分类两大类,错误ERROR
和Exception
.
Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
异常处理机制:
try{// try监控区域
// 可能发生异常的代码块
}catch(想要捕获的异常类型){
//捕获异常,处理异常(输出提示或者进行其他操作)
}catch(){
//...(可以捕获多个异常,范围从前往后依次扩大,前面的catch捕获异常之后后面的catch就不会再执行
}finally{ //处理善后工作,不论异常是否捕获,都会执行
// 最终执行代码块
}
throws 和throw
throws
关键字是用于方法声明中,用于表示该方法可能会抛出某种类型的异常。throw
键字用于在代码块中手动抛出一个异常对象。它可以用于任何地方,包括方法、构造器、代码块等。通过throw关键字,我们可以抛出自定义异常或者Java标准库中已定义的异常。当我们手动抛出一个异常时,程序将立即停止执行当前代码块,并开始查找与该异常匹配的异常处理器idea 快捷键: 选中对应的代码之后按下,Ctrl+ Alt+T,可以选择对该代码进行异常捕获或者循环嵌套
package com.dande.oop.demo04;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入要运算的两个整数,用空格隔开:");
int a = 0;
int b = 0;
Scanner scanner = new Scanner(System.in);
a = scanner.nextInt();
b = scanner.nextInt();
// double result1 = new Test().divide(a,b);
// System.out.println(result1); // 抛出异常,程序终止
// double result2 = new Test().divide2(a,b);
// System.out.println(result2); //Infinity
double result3 = new Test().divide3(a,b);
System.out.println(result3); // Finally ! Infinity
scanner.close();
}
public double divide(int a,int b){
if(b==0){
throw new ArithmeticException(); // 在方法中主动抛出异常
}else{
return a/((double)b);
}
}
// 在方法声明时抛出异常
public double divide2(int a,int b)throws ArithmeticException{
return a/((double)b);
}
// 使用try catch 捕获并处理异常
public double divide3(int a,int b){
double result =0;
try {
result = a/((double)b);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally!!");
}
return result;
}
}
package com.dande.oop.demo04;
//自定义的异常类
public class MyException extends Exception{
// 异常处理:如果传入的数字大于100,则抛出异常
private int detail;
public MyException() {
}
public MyException(int a){
this.detail = a;
}
// toString 方法相当于异常的打印信息
@Override
public String toString() {
return "MyException{" +
"detail=" + detail +
'}';
}
}
package com.dande.oop.demo04;
public class Test {
// 可能会存在异常的方法
static void test(int a) throws MyException { //抛出异常给方法的调用者
System.out.println("传递的参数为:"+a);
if(a>100){
throw new MyException(a); // 抛出异常
}
System.out.println("OK");
}
//public static void main(String[] args) throws MyException{
public static void main(String[] args) {
try {
test(102); //调用方法时捕获处理异常或者对调用方法的方法声明出继续用throws抛出异常
} catch (MyException e) {
// e.printStackTrace();
System.out.println(e);
}finally{
System.out.println("Finish");
}
}
}
try-catch
处理catch(Exception)
来出来可能会被遗漏的异常printStackTrace()
去打印输出