JAVA-10.14/10.15

本文深入讲解Java中的匿名对象、封装、this关键字、继承等核心概念,通过实例剖析代码块、静态成员、方法重写与重载的区别及应用。
一. 匿名对象
定义: 没有名字的对象。
意义: 节省代码,并且很多情况下是针对某个方法只需要调用一次的情况下。
匿名对象可以调用方法,也可以给成员变量赋值。 同时也可以作为方法的参数进行传递。
主要的作用就是节省代码量,使代码结构更优雅。
二. 封装
1.概念: 隐藏对象的属性和细节,仅对外提供公共的方法进行访问。
2.private
a. 当类的成员变量使用private 修饰符修饰,那么就不可以直接访问到该成员变量.
b. 当使用private 修饰的成员变量或者成员方法,仅能在本类中使用
c. private 对于main 方法的修饰,也是可以产生作用的.

javaBean:
是这样一类的类:
他的所有成员变量都使用private 进行修饰,并且对外提供可访问的设置值和获取值的set,get方法。不同的应用场景,可能命名
不同,数据库的应用中称为POJO类.
class Person{
 private String name;
 private int age;
 void setName(String nameParm){
  name = nameParm;
 }
  String getName(){
  return name;
 }
 void setAge(int ageParm){
  age = ageParm;
 }
  int getAge(){
  return age;
 }
  void speak(){
  System.out.println(name+" . "+age);
 }
 public static void main(String[] args){
  Person person = new Person();
  person.setName("diffo");
  person.setAge(30);
  person.speak();
 }
}
class DemoBean{
  static void main(String[] args){
  Person person = new Person();
  person.setName("diffo");
  person.setAge(30);
  person.speak();
 }
}

main方法细节:
a.每个类中都可以存在main方法,但是当执行的时候,会优先查看public 的class 中是否有main 方法.
b.如果没有public 的class, 那么会按照文件名优先查找类中的main方法
c.必须定义为public.
三. 优先原则:
优先原则: 对于一个类的成员方法来说,如果传递的形参的变量名称和类的成员变量名称相同,jvm在处理的时候优先当做方法的形参来处理.
四. this 关键字
1.含义:
代表了当前对象的引用.可以理解为,当前谁来调用,那么方法中的this 就代表谁。
对于成员变量可以区分出来的场景,this 可加也可以不加,实际效果相同。但是对于实现javaBean/POJO 来说,我们建议都加上在setXXX,getXXX方法中.
this:可以加在成员变量的前面来指定对应的引用,也可以加在成员方法的前面。
五. 初始化类成员变量的方式
a.在定义成员变量的同时进行赋值.
b.提供外界可访问到的方法,在方法中进行赋值.
c.通过构造方法进行赋值.
六. static
a.随着类加载而加载 静态方法区中来保存静态成员变量
b.优先于对象创建
Person.className = "java";
c.被类的所有对象共享 静态的成员变量会保存在该class的静态方法区中,所以每个对象看到的都是同一份.
d.可以通过类名来访问也可以通过对象名来访问。效果是一样的。
e.推荐通过类名来访问
f.静态的成员,一般称为类相关的成员。
f.static 修饰符既可以修饰成员变量,也可以修饰成员方法。 且修饰之后,就可以通过类名来直接访问到。
g.this变量在静态方法中不可以使用
h.静态方法中只能访问静态成员变量和静态方法。
  非静态方法既可以访问静态成员和方法也可以访问非静态成员和方法。
  非静态虽然可以访问静态的方法,但是不建议这样做。
工具类.
全部都是静态的方法。所以可以通过 类名.functionName() 方式来访问。
一般的话,都会对默认构造方法进行私有化处理,来防止别人使用时习惯性的创建对象来调用方法。

public static void main(String[] args){
   Square square = new Square();
   square.setLength(2);
   System.out.println(SquareUtil.getCircumLength(square));
   System.out.println(SquareUtil.getArea(square));
 }
 
}
//pojo类
class Square{
  private int length;
  void setLength(int length){
  this.length = length;
 }
 
 int getLength(){
  return this.length;
 }
}
//正方形工具类
class SquareUtil{
  private SquareUtil(){
  
 }
 static  int getCircumLength(Square square){
  return 4*square.getLength();
 }
 static   int getArea(Square square){
  return square.getLength()*square.getLength();
 }
}



一. 代码块
(使用{ } 括起来的代码,称为代码块)
分类: 根据它位置和声明的不同,我们可以将代码块分为      局部代码块,构造代码块,静态代码块,同步代码块(多线程涉及).
a. 局部代码块
限定了变量的生命周期,变量在局部代码块中定义的,那么出来局部代码块之后,就访问不到了。在局部代码块中定义的变量,在出了代码块之后,内存就会释放掉。
作用: 主要就是节约内存.
局部代码块中定义的变量,虽然说作用域是局部的,但是如果存在外部嵌套的代码块,且在局部代码块定义之前就定义了某个变量,那么在我们局部的代码块中就不可以定义相同名称的变量。
但是如果在局部代码块执行之后,去定义一个和局部代码块中相同名称的变量,是可以的。因为局部代码块中的变量已经失去了作用域范围。
b.构造代码块
概念: 类中方法外出现,每次调用构造方法的时候,都会优先先调用构造代码块。
特点: 每创建一个对象,都会调用一次我们的构造代码块.
作用: 如果存在很多重载的构造方法,而且每个里面需要执行 相同的逻辑,那么就可以考虑将这些代码提取到构造代码块中来执行。
让我们代码结构更简练。增强了维护性.    使用场景其实不太多见。
c.静态代码块
概念: 类中方法外出现,但是用static 来进行修饰。
特点: 随着类加载的时候执行。
用处: 适用于整个软件的生命周期中,只需要执行一次的业务逻辑代码。 比如我们之后数据库的操作.
代码示例:
 public class Demo2{
  static{
   System.out.println("demo2 静态代码块");
 }
 
  public static void main(String[] args){
  
      Person person = new Person();
      System.out.println("--------------------");
      Person person1 = new Person(20);
 }
 
}
class Person{
   int age;
   int[] num;
   static{
  System.out.println("调用了静态代码块");
 }
 
 {
  //构造代码块
  System.out.println("构造代码块");
 }
 
 //默认的构造方法
 Person(){
  System.out.println("默认构造");
  // 数组成员变量我们依次赋值
 }
 
 Person(int age){
  this.age = age;
  System.out.println("非默认构造");
  
  // 数组成员变量我们依次赋值
   }
 }

二. 继承
特点
1. 子类继承父类,继承父类的成员变量和成员方法。但是他们各自拥有的各自的成员变量,所以他们的值,并不会继承。
2. 对于父类中的私有成员变量和私有方法,子类是无法继承的。
继承优点:.     提高了代码的复用性      .提高了代码的维护性
继承缺点:   类的耦合性增强了。
开发的原则:
高内聚,低耦合.
耦合: 类和类之间的关系
内聚: 自己独立完成某件事情的能力.
3.只支持单继承,但是可以支持多层继承.   继承是相互叠加的,子类继承的时候,会递归似的寻找父类中是否还存在继承,会继承整个层级直到最根部类的属性和方法。
4.对于构造方法是无法继承的。 但是有办法可以调用父类的构造方法。

继承关系中访问成员变量:
a.不同名的成员变量
子类可以直接访问和使用父类继承的非私有的成员变量
b.同名的成员变量
优先原则: 如果子类中定义了和父类中相同名字的成员变量,会优先访问子类的该变量
如果想要依然访问到父类中的同名变量,我们需要加上super关键字来获取

继承关系中访问成员方法:
a.不同名的方法
子类可以直接调用到父类的方法
b.同名的方法
当父类和子类出现同名方法的时候(同名方法: 指的返回值类型(父子类关系是可以的),方法名称以及方法接收的形参列表要一模一样)
在这种情况下:
当我们子类调用该方法时,会有优先原则的处理,就是会调用子类的该方法。

this: 当前对象的引用    可以访问到子类中的变量,也可以访问到父类中的变量  可以访问子类的方法,也可以访问父类的方法。
super: 父类对象的引用    访问父类中的变量   只能够访问父类的方法
我们一个文件在编译之后产生的.class 文件的数量,取决于在该文件中定义的class的数量。(非内部类)
而且是不引入其他类的情况下。

eg:
public class ClassTest1{
 public static void main(String[] args){
   Square square =new Square();
   System.out.println(square.getSumLength());
   System.out.println(square.getArea());
   Rectangle rectangle = new Rectangle();
   System.out.println(rectangle.getSumLength());
   System.out.println(rectangle.getArea());
 }
}
class Square{
 
  private int lengthOfSide = 10;
 
  int getSumLength(){
   return 4*lengthOfSide;
 }
 
 int getArea(){
  return lengthOfSide*lengthOfSide;
 }
}
class Rectangle extends Square{
 int width = 4;
 int height = 5;
 int getSumLength(){
  return (width+height)*2;
 }
  int getArea(){
  return width*height;
 }
}

方法的重写:
存在于继承关系中,子类中定义的方法和父类中的方法完全一样的时候(返回值类型父子类关系是可以的),我们在通过子类对象来访问该方法的时候,就会调用到子类的方法。
方法重写注意事项:
子类不能重写父类的私有方法.
子类重写父类方法的时候,提供的访问权限不能更低.
子类覆盖父类方法,如果父类是静态方法的话,子类也必须是静态方法才可以成功覆盖,也就是重写。
方法重载:
同一个类中,如果我们有多个相同方法名的方法,但是他们的形参列表是不同的,那么这种方式我们就称为方法的重载。
在调用的时候,jvm能够通过不同的形参来区分到我们到底调用的是哪个方法。
关于方法重写和方法重载的返回值约束:
方法重载: 仅返回值不同是不能重载的。必须参数列表不同。
方法重写: 返回值类型(父子类关系是可以的) 要求返回值类型也要相同的.

继承中构造方法的调用:
特点:
1. 创建子类对象的时候,一定会优先去创建父类的对象。 因为要创建父类对象,所以就需要去调用到父类的构造方法.
2. 对于我们所有的类的构造方法的第一行,第一行在我们没有自己添加this(...)或者super(...)的情况下都会去帮我们默认的添加
super()
如果父类中不存在默认的构造,子类依然要创建对象,那么子类就需要显示的指明调用的是哪一个父类对象,才能保证父类对象
创建的成功。
明确一点:
a.一定要保证父类对象的创建成功.
b.构造方法的第一行,如果我们添加了自己调用的this(...),或者super(...), 系统就不会为我们默认的添加super().
c.我们的this(...)或者super(...) 必须放到第一行。二者只能有其一

三. final关键字
a.final修饰类    final如果修饰一个类,该类不能被继承.
b.final修饰类的成员变量   该成员变量的值不可修改。
问题: 那么什么时候初始化这个值?
在对象创建之前都可以.
a.构造代码块中可以进行初始化
b.构造方法中可以进行初始化
c.定义成员变量的时候,可以直接进行初始化.
注意一点: 这三种方式同时只能用一种。
在大多数的场景下,我们的final成员变量都会配合public static 一起使用.

静态成员变量的初始化时机:
a.在创建静态final成员变量的时候,直接进行初始化。
b.在静态代码块中进行初始化.

















[root@yfw ~]# cd /opt/openfire [root@yfw openfire]# sudo systemctl stop openfire [root@yfw openfire]# rm -rf /opt/openfire/embedded-db [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/conf [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/logs [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/plugins [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/lib [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/conf [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/logs [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/plugins [root@yfw openfire]# sudo chown -R openfire:openfire /opt/openfire/lib [root@yfw openfire]# ls -l /opt/openfire/conf/openfire.xml -rw-r--r-- 1 openfire openfire 874 Nov 15 16:25 /opt/openfire/conf/openfire.xml [root@yfw openfire]# rm -f /opt/openfire/logs/openfire.pid [root@yfw openfire]# sudo systemctl start openfire [root@yfw openfire]# tail -f /opt/openfire/logs/nohup.out at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source) ~[derby-10.14.2.0.jar:?] at org.apache.derby.impl.jdbc.EmbedPreparedStatement42.<init>(Unknown Source) ~[derby-10.14.2.0.jar:?] at org.apache.derby.jdbc.Driver42.newEmbedPreparedStatement(Unknown Source) ~[derby-10.14.2.0.jar:?] at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) ~[derby-10.14.2.0.jar:?] at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source) ~[derby-10.14.2.0.jar:?] at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:696) ~[commons-dbcp2-2.9.0.jar:2.9.0] at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:696) ~[commons-dbcp2-2.9.0.jar:2.9.0] at org.jivesoftware.openfire.XMPPServer.verifyDataSource(XMPPServer.java:1011) ~[xmppserver-5.0.2.jar:5.0.2] ... 11 more 启动服务器时出错。有关详细信息,请查看日志文件。
11-16
你已经完成了几乎所有正确的准备工作,包括: - ✅ 停止服务 - ✅ 删除旧数据库目录 `embedded-db` - ✅ 修复了 `/conf`, `/logs` 等关键目录的权限 - ✅ 删除 `.pid` 文件 - ✅ 重新启动 OpenFire 但现在日志中仍然报错: ``` Caused by: java.sql.SQLSyntaxErrorException: Table 'ofID' already exists. ``` --- ## 🚨 核心问题:**OpenFire 尝试创建表时发现“表已存在”** 这个错误说明了一个关键事实: > 🔴 **虽然你删除了 `/opt/openfire/embedded-db`,但 OpenFire 的 Derby 数据库文件其实还残留在另一个位置!** Derby 默认会把数据库存放在 **当前工作目录下的 `embedded-db`**,而 OpenFire 启动时的工作目录可能不是 `/opt/openfire`! --- ## 🔍 深入分析:Derby 数据库存放路径从哪来? OpenFire 使用以下配置决定数据库路径(在首次安装前): ```xml <!-- 默认内嵌数据库 URL --> <property name="jdbcProvider.databaseUrl" value="jdbc:derby:/opt/openfire/embedded-db;create=true"/> ``` 但如果这个配置已经被写入某个地方(比如残留的 `openfire.xml` 或 Derby 在其他路径下创建了数据),它就会去那个位置建表。 而你现在看到的错误: ``` Table 'ofID' already exists ``` 👉 表明:**Derby 找到了一个已存在的数据库,并试图再次运行初始化 SQL,导致冲突。** --- ## ✅ 正确解决方案:彻底清理所有可能的 Derby 数据库残留 ### 🔧 步骤 1:确认当前工作目录下是否有隐藏的 Derby 数据库 OpenFire 服务运行时的“当前目录”可能是 `/`、`/root` 或 `/opt/openfire`,这取决于你的 `systemd` 配置。 请检查以下几个常见位置是否残留 `derby.log` 或数据库文件夹: ```bash # 查看根目录下是否有 derby.log ls -la / | grep derby # 特别检查这些路径: find / -name "derby.log" 2>/dev/null find / -name "openfire.db" -o -name "embedded-db" 2>/dev/null ``` 如果你发现类似: ``` /var/lib/openfire/embedded-db/ /home/openfire/embedded-db/ /tmp/embedded-db/ /opt/openfire/embedded-db/ ← 虽然你删过,但也许被重建了? ``` 立即删除它们: ```bash sudo rm -rf /var/lib/openfire/embedded-db sudo rm -rf /home/openfire/embedded-db sudo rm -rf /tmp/embedded-db ``` > 💡 **重点:很多用户忽略了 `/var/lib/openfire` 这个路径!它是某些 RPM 包默认的数据目录。** --- ### 🔧 步骤 2:确保 `openfire.xml` 完全不存在(让它重置) 你之前执行了: ```bash ls -l /opt/openfire/conf/openfire.xml ``` 输出显示该文件存在(874 字节),这意味着 **OpenFire 认为你已经安装过了**,不会进入 Setup 模式! 🛑 即使你设置了内嵌数据库,如果 `openfire.xml` 存在且指向一个损坏或不一致的数据库,就会导致这种“表已存在”的矛盾状态。 所以必须删掉它: ```bash rm -f /opt/openfire/conf/openfire.xml ``` ✅ 只有当 `openfire.xml` 不存在时,OpenFire 才会在启动时强制进入 **Setup Mode(设置向导模式)** --- ### 🔧 步骤 3:确保 systemd 的 WorkingDirectory 正确 编辑服务文件: ```bash sudo vi /etc/systemd/system/openfire.service ``` 确保有这一行: ```ini WorkingDirectory=/opt/openfire ``` 否则 Java 启动时的“当前目录”可能是 `/`,导致 Derby 在 `/embedded-db` 下创建数据(你根本找不到!) 完整推荐配置: ```ini [Unit] Description=OpenFire XMPP Server After=network.target [Service] Type=forking User=openfire Group=openfire PIDFile=/opt/openfire/logs/openfire.pid ExecStart=/opt/openfire/bin/start.sh ExecStop=/opt/openfire/bin/stop.sh Restart=on-failure WorkingDirectory=/opt/openfire [Install] WantedBy=multi-user.target ``` 保存后重载: ```bash sudo systemctl daemon-reload ``` --- ### 🔧 步骤 4:最终清理 + 重启 ```bash # 停止服务 sudo systemctl stop openfire # 再次确认 embedded-db 被删干净 rm -rf /opt/openfire/embedded-db # 删除配置文件 rm -f /opt/openfire/conf/openfire.xml # 删除 pid 文件 rm -f /opt/openfire/logs/openfire.pid # 修复所有权(再执行一次) sudo chown -R openfire:openfire /opt/openfire sudo chmod -R 755 /opt/openfire # 启动服务 sudo systemctl start openfire ``` --- ### 🔧 步骤 5:查看日志,等待 Setup 模式 ```bash tail -f /opt/openfire/logs/nohup.out ``` 你应该看到: ``` INFO [org.jivesoftware.admin.SetupFilter] Setup mode detected. Redirecting to setup page. ``` ✅ 出现这句就代表成功进入安装流程! 然后访问浏览器: 👉 [http://192.168.0.142:9090](http://192.168.0.142:9090) 点击 “Continue” 开始安装。 --- ## 🛠️ 额外建议:手动指定数据库路径(避免歧义) 你可以强制 OpenFire 使用明确路径,在首次启动前修改其行为(虽然不能预先写 `openfire.xml`,但可以控制环境变量)。 不过最简单的方法是保证: - `openfire.xml` 不存在 → 触发 Setup 模式 - `embedded-db` 目录不存在 → 触发新建数据库 - 工作目录正确 → 避免路径混乱 --- ## ✅ 总结操作清单(最后冲刺) | 步骤 | 命令 | |------|------| | 1. 停止服务 | `sudo systemctl stop openfire` | | 2. 删除数据库 | `rm -rf /opt/openfire/embedded-db` | | 3. 删除配置 | `rm -f /opt/openfire/conf/openfire.xml` | | 4. 删除 pid | `rm -f /opt/openfire/logs/openfire.pid` | | 5. 检查全局残留 | `find / -name "embedded-db" 2>/dev/null` → 全部删除 | | 6. 修复权限 | `chown -R openfire:openfire /opt/openfire` | | 7. 确保 systemd 工作目录 | `WorkingDirectory=/opt/openfire` | | 8. 重载并启动 | `sudo systemctl daemon-reload && sudo systemctl start openfire` | | 9. 查看日志 | `tail -f /opt/openfire/logs/nohup.out` | | 10. 浏览器访问 | [http://192.168.0.142:9090](http://192.168.0.142:9090) | --- 🎯 **只要 `openfire.xml` 和 `embedded-db` 都不存在,OpenFire 必定进入 Setup 模式!** 你现在离成功只有一步之遥! --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值