Строки в Java неизменяемы. Это означает, что всякий раз, когда вы пытаетесь изменить / изменить строку, вы получаете новый экземпляр. Вы не можете изменить исходную строку. Это сделано для того, чтобы эти экземпляры строк могли кэшироваться. Типичная программа содержит множество ссылок на строки и кеширование этих экземпляров, что может уменьшить объем памяти и увеличить производительность программы.
При использовании оператора == для сравнения строк вы не сравниваете содержимое строки , но фактически сравнивают адрес памяти. Если они равны, в противном случае они вернут true и false. Если значение равно в строке, сравнивает содержимое строки.
Итак, вопрос в том, что все строки кэшируются в системе, как получается ==
возвращает false, тогда как equals возвращает true? Ну, это возможно. Если вы создадите новую строку, например String str = new String("Testing")
, вы создадите новую строку в кеше, даже если в кеше уже содержится строка с тем же содержимым. Короче говоря, "MyString" == new String("MyString")
всегда будет возвращать false.
Java также говорит о функции intern (), которая может использоваться в строке, чтобы сделать ее частью кеша, поэтому "MyString" == new String("MyString").intern()
вернет true.
Примечание: == оператор намного быстрее, чем равен только потому, что вы сравниваете два адреса памяти, но вы должны быть уверены, что код не создает новые экземпляры String в коде. В противном случае вы столкнетесь с ошибками.
Я считаю, что в случае наследования вы должны реализовать Coding
самостоятельно. То есть вы должны указать CodingKeys
и реализовать init(from:)
и encode(to:)
как в суперклассе, так и в подклассе. WWDC видео (около 49:28, на фото ниже), вы должны вызвать супер с суперкодером / декодером.
required init(from decoder: Decoder) throws {
// Get our container for this subclass' coding keys
let container = try decoder.container(keyedBy: CodingKeys.self)
myVar = try container.decode(MyType.self, forKey: .myVar)
// otherVar = ...
// Get superDecoder for superclass and call super.init(from:) with it
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder)
}
Видео, кажется, перестает показывать сторону кодирования (но это container.superEncoder()
для стороны encode(to:)
), но она работает примерно так же в вашей реализации encode(to:)
. Я могу подтвердить, что это работает в этом простом случае (см. Ниже код детской площадки).
Я все еще борюсь с каким-то нечетным поведением с гораздо более сложной моделью, которую я конвертирую из NSCoding
, у которой много новых типов (включая struct
и enum
), это демонстрирует это неожиданное поведение nil
и «не должно быть». Просто имейте в виду, что могут быть краевые случаи, связанные с вложенными типами.
Редактировать: вложенные типы, похоже, отлично работают на моей тестовой площадке; Теперь я подозреваю, что что-то не так с классами саморегуляции (подумайте о детях узлов дерева) с самим набором, который также содержит экземпляры этого класса под разными классами. Тест простого класса саморегуляции отлично декодирует (т. Е. Никаких подклассов), поэтому я теперь сосредоточиваю свои усилия на том, почему случай подкласса терпит неудачу.
Обновление 25 июня 17: Я закончил тем, что написал об этом Apple. rdar: // 32911973 - К сожалению, цикл кодирования / декодирования массива из Superclass
, который содержит элементы Subclass: Superclass
, приведет к тому, что все элементы в массиве будут декодированы как Superclass
(подкласс «init(from:)
никогда не вызывается, что приводит к потере данных или к худшему).
//: Fully-Implemented Inheritance
class FullSuper: Codable {
var id: UUID?
init() {}
private enum CodingKeys: String, CodingKey { case id }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
}
}
class FullSub: FullSuper {
var string: String?
private enum CodingKeys: String, CodingKey { case string }
override init() { super.init() }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let superdecoder = try container.superDecoder()
try super.init(from: superdecoder)
string = try container.decode(String.self, forKey: .string)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(string, forKey: .string)
let superdecoder = container.superEncoder()
try super.encode(to: superdecoder)
}
}
let fullSub = FullSub()
fullSub.id = UUID()
fullSub.string = "FullSub"
let fullEncoder = PropertyListEncoder()
let fullData = try fullEncoder.encode(fullSub)
let fullDecoder = PropertyListDecoder()
let fullSubDecoded: FullSub = try fullDecoder.decode(FullSub.self, from: fullData)
Оба свойства супер- и подкласса восстанавливаются в fullSubDecoded
.
Мне удалось заставить его работать, если мой базовый класс и подклассы соответствуют Decodable
вместо Codable
. Если бы я использовал Codable
, он бы разбился нечетными способами, такими как получение EXC_BAD_ACCESS
при доступе к полю подкласса, но отладчик мог без проблем отображать все значения подкласса.
Кроме того, передача супердекодера в базовый класс в super.init()
не сработала. Я просто передал декодер из подкласса в базовый класс.
Как насчет использования следующего пути?
protocol Parent: Codable {
var inheritedProp: Int? {get set}
}
struct Child: Parent {
var inheritedProp: Int?
var title: String?
enum CodingKeys: String, CodingKey {
case inheritedProp = "inherited_prop"
case title = "short_title"
}
}
Дополнительная информация о композиции: http://mikebuss.com/2016/01/10/interfaces-vs-inheritance/
Найдено эта ссылка - перейти к разделу наследования
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(employeeID, forKey: .employeeID)
}
Для декодирования я сделал это:
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let values = try decoder.container(keyedBy: CodingKeys.self)
total = try values.decode(Int.self, forKey: .total)
}
private enum CodingKeys: String, CodingKey
{
case total
}
container.superDecoder()
не требуется. super.init (из: декодер) достаточно – Lal Krishna 6 June 2018 в 09:39super.init(from: decoder)
– Lal Krishna 7 June 2018 в 04:55