java初学——面向对象
文章目录
补充关于方法的相关内容
方法的使用
程序代码越简单明了越好,为了避免重复的代码多次敲写,可以将重复的代码抽成一个方法,提高代码复用率。
方法递归:
在方法里面调用自己叫做递归;
public static void main(String[] args) {
System.out.println("求n的阶乘");
System.out.println(a(5));
}
static int a(int n){
if(n==1) {
return 1; // 当n==1时,得到结果网上返回
}else {
return n*a(n-1); // 调用自己
}
}
如图
可变参数的方法
求n个数的和,要求传入参数不确定,有可能是sum(x),sum(x,y),sum(x,y,z),
sum(x,y…z),因此对于可变参数我们不能写无数个这样重复代码的方法。
因此有了对付参数不确定格式
如下:
static int sum(int... nums){
//类似于创建一个数组
int num = 0;
for(int i = 0 ; i<nums.length ; i++){
num += nums[i]; //依次求和的操作
}
return num;
}
方法的重载
对于一些方法,表达意思一样,但是传入参数不一样,可以用方法的重载,打到不改变方法名,是一样的操作。求两个数的和,但是没有告诉类型,我们可以以整型和浮点型为例
public static void main(String[] args) {
System.out.println(sum(1,5)); // 输出为6,调用第一个方法
System.out.println(sum(1.2,5)); // 输出为6.2,调用第二个方法
}
static int sum(int x,int y){
return x+y;
}
static double sum(double x,double y){
return x+y;
}
补充关于数组的相关内容
模板如下
// 创建固定元素数组
// 数据类型 [] 数组名称 = {数组内容1,数组内容2,.......数组内容n};
String [] name = {"张三","李四"};
System.out.println(name[0]) // 输出为张三,数组从0开始到n-1,结束,n为数组元素个数
// 创建数组,但是大小不固定
// 数组类型 [] 数组名称 = new 数据类型 [数据长度(可以为固定正数,也可以是n]
// n要在前面声明int型数的大小
String [] name= new String [5];
// 存入数据
Scanner input = new Scanner(System.in);
for (int index = 0 ; index < name.length ; index++){
String str = input.next();
name[index] = str ;
}
// 打印数据也叫做遍历,数组名.length也叫做该数组的大小n;
for (int index = 0 ; index < name.length ; index++){
System.out.println(name[index]);
}
// 多维数组的创建,以二维数组为例
// 数组类型 [][] 数组名称 = new 数据类型 [必写n或者是固定数][(可写可不写)]
// 1.如果数组第二个不写,则还要在每个数组元素开辟几个空间形成二维数组
// 如下:
String [][] name = new String[8(m)][];
name[0] = new String[4(n)]; // 形成8*4/(m*n,m,n可以再前面写)个存储Sting类型的空间
多维数组类似,一层一层创建,或者直接创建固定值的
注:数组无论怎么样创建数组的大小一定是固定的,如果要进行扩容,重新创建更大的变量,再依次赋值进去,最后根据gc自动检测无用的,会回收之前的从而实现扩容。
数组的排序方法
冒泡排序,
思想为相邻两个元素进行比较和交换,使最大或最小的元素在其开头或者最后,随后较大的元素开始移到最大的后面,最后依次排好,就像生活中排队一样,高点的站后面,一个一个依次排队,分别和后面人比较,看比他高还是矮,矮的不动,高的往后一个,然后接着比较。
/**
* 这只是一种,从前往后升序,其次还有多种从后往前降序等
* 把这个排序抽成一个方法如下
*/
static void BubbleSort(int a[]){
for (int i = 0 ;i<a.length ; i++){ // 外层循环控制的每次比较个数
for(int j = 1 ; j < a.length-i; j++){ // 内层控制每次从第一个开始比较,比较次数
if(a[j-1]>a[j]){ // 如果前一个比后一个大,则交换
int temp = 0;
temp = a[j-1];
a[j-1] = a[j];
a[j] = temp;
}
}
}
}
查找方法
直接查找
static void Seek(int num,int a[]){
for (int i = 0 ;i < a.length ; i++){
if(num == a[i]){
System.out.println("找到了,在第"+i+1+"位置上");
break;
}
}
System.out.println("没有找到元素");
}
折半查找,面对数据很多的情况下,且数据在内部排序完成时进行
// 这个折半使用前提数据排序好的
static void halfSeek(int a[],int num){
int min = 0; // 让初始等于数组前后坐标
int max = a.length-1;
int mid = (max +min)/2; // 找到中间值
while (true) {
if(mid==min && mid!=num){
System.out.println("没有找到该数");
break;
}
if (num < a[mid]) {
max = mid - 1;
} else {
min = mid + 1;
}
mid = (max + min) / 2;
if (num == a[mid]) {
System.out.println("找到该数了,该数的位置为第"+(mid+1)+"个元素");
break;
}
}
}
面向对象基础
一切都可以皆对象,对于一个问题时都可以封装为一个类,使其保证较高的代码阅读能力和使用能力,比单纯的方法更加具有实用效应

对象
1.引入
在生活中,各种东西生物都有自己的属性和特点,比如人有自己的姓名,身份证号,家庭地址,电话号码,通过这些家庭住址,姓名就可以找到这个人,再比如说,人与动物之间有相同的特点,都要生存,休息等,这些共有属性我们也可以在程序表达,也有不同点,鸟会飞,人会使用工具,这些衍生出来的不同点,我们又可以表达属于不同的特点这些我们可以写作类。
在类中,我们也可以表达出相同的意思,一个类包括成员变量和成员方法。在成员变量和方法我们要宣称修饰符,就像生活中有的属性年龄,体重不愿意公开说,可以设置私有(private),有的得奖的方法战绩可以宣传出去就可以设置共有(public),创造实例即为对象,对象实例化用new关键字来完成,就可以使用它了。
面向对象分为三种
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象程序
同时具有三大特征:封装性,继承性,多态性。
示范代码如下(示例):
public class Person {
// 私有一个属性年龄
private int age;
// 默认一个属性名字,默认为default
String name;
// 成员方法
// 没有生成构造函数系统会默认生成一个
public Person() {
}
public Person(String name) {
// 构造函数的重载
this.name = name;
}
public int getAge() {
// 显示年龄
return age;
}
public void setAge(int age) {
// 获取年龄
this.age = age;
}
public void show(){
System.out.println("我的名字是"+name+",我今年"+age+"岁了!");
}
}
public static void main(String[] args) {
// 生成对象 对象类型 对象名 = new 对象类型();
Person p = new Person("张三");
p.setAge(18); // 设置年龄
p.show(); // 输出为 我的名字是张三,我今年18岁了!
}
注:生成对象时,在使用相应方法时,实例对象名.相应的方法操作,如上面的,p.show();
this关键字
this关键字,指的是自己实例对象的属性或者方法
public Person() {
this("zhang san",18) ; // 调用自身两参数进行初始化
System.out.println(name +age);
}
注:this关键字初始化调用自身构造方法时,必须写在构造方法的第一排
不能写成下面这种形式
public Person() {
System.out.println(name +age); // 报错,初始化应该加载构造函数,
//不能使用其他的
this("zhang san",18) ;
}
在IDEA中,按住Alt + Insert 会弹出针对对象的快捷生成方式,常用的几种功能,有的也是方法就是函数,所以写的时候把函数看成方法就行了
当然不用快捷键,在这里找到
2.基础介绍
各种方法
1.构造方法,在对象生成实例时,会做准备工作,类似于初始化这样的操作,如上面的第一个功能Constructor,可以选择无参的构造函数,也可以初始化有参数的构造方法
代码如下(示例):
public class Person {
public Person() {
System.out.println("我是构造函数");
}
}
// 在主函数中
public class Main1 {
public static void main(String[] args) {
// 生成对象 对象类型 对象名 = new 对象类型();
Person p = new Person(); // 输出为:我是构造函数
}
}
2,get,和set
快捷键可以自动为你生成相关的成员设置和显示成员变量,这样做的好处在于封装在内部,private修饰的,只能通过内部方法来访问或者改变,这样更加安全可靠。
public int get成员变量() {
return 成员变量;
}
public void 成员变量(数据类型 成员变量) { // 获取年龄
this.成员变量 = 成员变量;
}
3.equals()
重写equals函数,目的为了比较成员涉及的变量是否相同
如果不重写无法进行比较,只能比较单个属性,却不能得到变量整体相等
这里我们只勾选年龄和分数相同,就认为两个实例对象相等
生成如下
@Override
// Object 是所有对象的父类,因此可以说传入一个实例对象
public boolean equals(Object o) {
// 本身就和上一个对象相同,true
if (this == o) return true;
// 不是这个Person这个类型,false
if (!(o instanceof Person)) return false;
// 将传入的对象,强转成Person类型,父类强制转换为Person的一个子类
Person person = (Person) o;
// 判定勾选的年龄和分数
return age == person.age && score == person.score;
}
@Override
public int hashCode() {
return Objects.hash(age, score);
实际操作如下,
Person p1 = new Person("zhang san",18,1001,98);
Person p2 = new Person("li si",18,1002,98);
Person p3 = new Person("wang er ma zi",19,1002,98);
System.out.println(p1.equals(p2)); // 输出为true
System.out.println(p2.equals(p3)); // 输出为false
4.toString
重写toString函数,如果不重写代码如下
Person p1 = new Person("zhang san",18,1001,98);
// 输出为com.java.class.Person@651
// toSing是Object的一个方法,返回该文件地址+@+哈希码16位无符号字符串
// 返回字符串表现形式,如果不重写不更加具体看到我们想看到的
System.out.println(p1.toString());
重写后
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", number=" + number +
", score=" + score +
'}';
}
// 在主函数内输入
//输出为Person{name='zhang san', age=18, number=1001, score=98}
System.out.println(p1.toString());
匿名对象
匿名,没有名字,只能使用一次,下次再也找不到上一个的操作了
原来对象每次使用都 对象名 名字 = new 对象名();
现在我们直接可以使用右边不取名字,调用一次的操作。
比如上面的输出默认的姓名名字年龄分数,可以直接使用
new Person().toSing;,其他调用方法一样,用生成对象的右边代替,使用一次的操作
继承与接口
继承
如果编写了一个类,但是想要完成两种属性两种操作又有区别,但是有相同点,依次有了继承,继承是继承父类的特征和行为,所以说子类有父类相同的操作,同时子类可以具有自己的行为,通过关键字extends继承于父类
语法模式
class 父类名{
}
class 子类名 extends 父类名{
}
代码如下
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
//继承Person
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
// 在主函数中,
Person p1 = new Person();
Student p2 = new Student();
p2.setAge(18); // 可以用父类的方法
p1.setNumber(123234); // 报错,父类无法使用子类的
继承可以多重继承,但是在java中无法多继承,即一个子类不能有多个父类,一个子类也可以被下一个所继承。
关键字super
super可以访问父类构造方法,调用父类的构造方法,就像初始化一样写在第一行,子类的构造方法,每生成一个实例就创建了一个父类,通过super可以调用父类的方法,代码如下
public Student(String name, int age, int number) {
// 每次传入三个属性进来,都会生成父类构造
super(name, age);
// 默认年龄18,姓名张三
super.setAge(18);
super.setName("zhang san");
最后,构造方法初始化为张三 18 加自己输入的number
this.number = number;
}
注:在使用super关键字时,父类构造必须放在第一排,但是和this构造函数放第一排产生矛盾,其实使用super系统调用this了,不用再写this来产生错误了。
方法的重写
对于父类有自己方法,子类也想实现相同类似的操作,可以将方法进行重写,可以调用子类的该方法与父类又既有差异性。
public class Person {
void say(){
System.out.println("I am Person!");
}
}
class Student extends Person{
//继承Person
@Override
void say() {
System.out.println("I am Student!");
// 这样重写调用子类的方法就显示不同
}
}
方法的重写(Override)与重载(Overload)的区别
- 1,发生的位置不同
- 重载是在一个类中
- 重写是在父类与子类中
- 2,参数的限制不同
- 重载的参数可以不相同
- 重写的参数必须相同
- 3 ,返回值类型不同
- 重载与返回值无关
- 重写必须一致
- 4访问权限
- 重载与访问权限没有关
- 重写子类的权限必须大于等于父类的权限
- 5,异常处理
- 重载与异常处理无关
- 重写异常范围可以更小但是不能抛出新的区别
接口
语法格式
interface 接口名称{
全局常量;(例如;int a =1;默认为static final int a=1;全局常量
抽象方法;(注,只能有抽象方法,不能有构造方法,只有名字没有实际意义)
}
抽象方法,只有方法前面的,没有{},例如void print();
实现类
class 子类 implements 父接口1 ,父接口2,父接口3,…{
}
如果又含有继承又有接口时格式如下
class 子类 extends implements 父接口1 ,父接口2,父接口3,…{
}
且接口可以继承,不同于类的继承有多继承格式如下
interface C extends A , B{
}
例如:
interface Person1{
int a = 8;
void print();
}
public class Person implements Person1{
@Override
public void print() {
System.out.println("接口的实现");
}
}
抽象类
抽象类·用 abstract class 声明
格式为
abstract class 抽象类名{
// 可以有抽象方法,也可以有构造方法
// 但是抽象方法必须有abstract修饰
public abstract void 方法名();
}
public abstract class Person2 {
public Person2() {
System.out.println("构造方法");
}
abstract void print();
}
public class Person extends Person2{
@Override
public void print() {
System.out.println("抽象类方法的实现");
}
}
注意,1,抽象类无法实现,所以不能用new生成实例化
2,一个抽象类必须被子类继承,子类不是抽象类要写出所有抽象方法的实现,没有实现完也是抽象类。
3,抽象类不能被final所修饰的,因为final修饰的不能有子类,而抽象类有子类才有意义
4,抽象类可以有构造方法,先调用父类的再调用子类的构造方法,和普通类继承一样,但是我们没法手动创建抽象对象,但是在jvm(虚拟机)创建;
5,抽象类必须用public或者protected修饰,用private修饰的抽象类无意义
但是接口比抽象类更加抽象,因此接口的使用更加常见,而抽象类使用较少
内部类和包装类
内部类
在一个类的里面再定义一个类,及class A{ class B{}},这种形式,相对于B来说A为外部内,对于A来说B就是内部类
class Outer {
private int x = 1;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
class Inner{
public void say(){
System.out.println("x="+x);
}
}
}
特点:内部类可以访问外部类的所有属性包括private或者static修饰的和成员方法
注意:当内部类有与外部相同的成员变量或者方法时,外部类会发生隐藏现象,及直接访问会访问到内部的,可以通过下面格式访问
外部类.this.成员变量(成员方法)
对于外部想要访问内部类结合上一张图片做下面操作
Outer outer = new Outer();
Outer.Inner inter = outer.new Inter();
根据内部类的位置分为四种:成员内部类,局部内部类,匿名内部类,静态内部类
上面也是成员内部类,外部如果不创建,无法使用内部类。
局部内部类,意思上来说就是局部的概念,有的对象我们可能只使用几次,后面就再也不会使用了,因此写到{ }内,就可以使用一次就不会再使用了。
public static void main(String[] args) {
int a = 5;
class Name{
// 写自己要做的成员方法或者是成员属性
}
Name name = new name();
name.xxxx; // 程序中只使用一两次完成的操作,之后不再使用
System.out.println(a); // 当内部使用外部的变量,
//外部就变为final修饰的,如果外部再将a变值则会报错
}
局部内部类调用外部的变量,外部默认变成final不可以改变的。解释一下
(当外面一a=5,在系统会备份一次(单独编译的字节码文件),如果外面改变了,里面备份和外部不一样,会发生错误,因此java避免这种错误,所以只能访问final型。)
匿名内部类,只使用一次的类,属于局部内的一种,和局部内部类,只是使用不同
public interface Person {
void say();
}
public static void main(String[] args) {
Person p = new Person() {
// 只使用一次的匿名内部类
@Override
public void say() {
} // 接口的实现
};
}
匿名内部类,必须有一个父类或者一个接口的实现类
规则:匿名内部类不能存在静态成员或者静态方法,如果是一个接口的实现,要实现所有未实现的方法,匿名内部类属于局部内部类,只能访问final的局部变量
静态内部类和其他内部类一样,只不过在前面类用static进行修饰
class Outer {
private int x = 1;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
static class Inner{
public void say(){
System.out.println("x="+x); // 不可以使用外部非静态类
//会出现错误,只有将上面改为static private int x,才可以访问
}
}
}
// 其次它和访问内部类有区别,可以生成内部类
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner(); // 直接生成内部类的对象
}
包装类
在系统以及做好的类,为了使我们更加便利,java提供了8种数据类型的包装类
基本数据类型 | 包装类 |
---|---|
int | Integer |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
byte | Byte |
short | Short |
long | Long |
除了int,char其他都是首字母大写
但是八种包装类分成两类
Character,Boolean都是Object的直接子类
Integer,Float,Double,Byte,Short,Long都是Number的子类
用到操作,常用的是将字符串转换为8种数据类型
// 以String转换为int为例
Scanner input = new Scanner(System.in);
System.out.println("请输入数据");
String str = input.nextLine();// 输入2235
int x = Integer.parseInt(str);
System.out.println("输入的数据为"+x); // 输出为:输入的数据为2235
其他转换方法只需要把前面的改为相应的包装类即可。
总结
总结面向对象将一些具有联系的形成一个整体,更贴近于事物运行模式,面向对象让我们进一步了解程序的运行模式,让我们从工人到设计师的转变。
难点在于多个类对象的加上数组的设计与实现。复杂交错。以及细节的一些方面处理。